]> code.delx.au - pulseaudio/blobdiff - src/daemon/main.c
client-conf: Remove redundant function parameters
[pulseaudio] / src / daemon / main.c
index 4891182733cf1285a1556391d156b6266b53c22f..02a8ea6493d6c64911ebf5af47dbdaff757e7459 100644 (file)
@@ -33,7 +33,6 @@
 #include <stddef.h>
 #include <ltdl.h>
 #include <limits.h>
-#include <fcntl.h>
 #include <unistd.h>
 #include <locale.h>
 #include <sys/types.h>
 #include <sys/mman.h>
 #endif
 
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
 #include <dbus/dbus.h>
 #endif
 
+#include <pulse/client-conf.h>
+#ifdef HAVE_X11
+#include <pulse/client-conf-x11.h>
+#endif
 #include <pulse/mainloop.h>
 #include <pulse/mainloop-signal.h>
 #include <pulse/timeval.h>
 #include <pulse/xmalloc.h>
-#include <pulse/i18n.h>
 
+#include <pulsecore/i18n.h>
 #include <pulsecore/lock-autospawn.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/core-error.h>
 #include <pulsecore/core-rtclock.h>
+#include <pulsecore/core-scache.h>
 #include <pulsecore/core.h>
-#include <pulsecore/memblock.h>
 #include <pulsecore/module.h>
 #include <pulsecore/cli-command.h>
 #include <pulsecore/log.h>
 #include <pulsecore/sioman.h>
 #include <pulsecore/cli-text.h>
 #include <pulsecore/pid.h>
-#include <pulsecore/namereg.h>
 #include <pulsecore/random.h>
 #include <pulsecore/macro.h>
-#include <pulsecore/mutex.h>
-#include <pulsecore/thread.h>
-#include <pulsecore/once.h>
 #include <pulsecore/shm.h>
 #include <pulsecore/memtrap.h>
+#include <pulsecore/strlist.h>
 #ifdef HAVE_DBUS
 #include <pulsecore/dbus-shared.h>
 #endif
 #include <pulsecore/cpu-arm.h>
 #include <pulsecore/cpu-x86.h>
+#include <pulsecore/cpu-orc.h>
 
 #include "cmdline.h"
 #include "cpulimit.h"
@@ -133,7 +130,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, const struct timeval
     }
 
     pa_timeval_add(pa_gettimeofday(&tvnext), 100000);
-    a->rtclock_time_restart(e, &tvnext);
+    a->time_restart(e, &tvnext);
 }
 
 #endif
@@ -202,15 +199,15 @@ static int change_user(void) {
         return -1;
     }
 
-    if (strcmp(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH) != 0)
+    if (!pa_streq(pw->pw_dir, PA_SYSTEM_RUNTIME_PATH))
         pa_log_warn(_("Home directory of user '%s' is not '%s', ignoring."), PA_SYSTEM_USER, PA_SYSTEM_RUNTIME_PATH);
 
-    if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid) < 0) {
+    if (pa_make_secure_dir(PA_SYSTEM_RUNTIME_PATH, 0755, pw->pw_uid, gr->gr_gid, true) < 0) {
         pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_RUNTIME_PATH, pa_cstrerror(errno));
         return -1;
     }
 
-    if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid) < 0) {
+    if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid, true) < 0) {
         pa_log(_("Failed to create '%s': %s"), PA_SYSTEM_STATE_PATH, pa_cstrerror(errno));
         return -1;
     }
@@ -254,6 +251,8 @@ static int change_user(void) {
         return -1;
     }
 
+    pa_drop_caps();
+
     pa_set_env("USER", PA_SYSTEM_USER);
     pa_set_env("USERNAME", PA_SYSTEM_USER);
     pa_set_env("LOGNAME", PA_SYSTEM_USER);
@@ -269,7 +268,7 @@ static int change_user(void) {
     if (!getenv("PULSE_STATE_PATH"))
         pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH);
 
-    pa_log_info(_("Successfully dropped root privileges."));
+    pa_log_info(_("Successfully changed user to \"" PA_SYSTEM_USER "\"."));
 
     return 0;
 }
@@ -343,6 +342,24 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {
 }
 #endif
 
+static char *check_configured_address(void) {
+    char *default_server = NULL;
+    pa_client_conf *c = pa_client_conf_new();
+
+    pa_client_conf_load(c);
+#ifdef HAVE_X11
+    pa_client_conf_from_x11(c);
+#endif
+    pa_client_conf_env(c);
+
+    if (c->default_server && *c->default_server)
+        default_server = pa_xstrdup(c->default_server);
+
+    pa_client_conf_free(c);
+
+    return default_server;
+}
+
 #ifdef HAVE_DBUS
 static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
     DBusError error;
@@ -363,7 +380,7 @@ static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const
     if (dbus_error_is_set(&error))
         pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
     else
-        pa_log_error("D-Bus name %s already taken. Weird shit!", name);
+        pa_log_error("D-Bus name %s already taken.", name);
 
     /* PA cannot be started twice by the same user and hence we can
      * ignore mostly the case that a name is already taken. */
@@ -383,25 +400,27 @@ int main(int argc, char *argv[]) {
     pa_daemon_conf *conf = NULL;
     pa_mainloop *mainloop = NULL;
     char *s;
+    char *configured_address;
     int r = 0, retval = 1, d = 0;
-    pa_bool_t valid_pid_file = FALSE;
-    pa_bool_t ltdl_init = FALSE;
+    bool valid_pid_file = false;
+    bool ltdl_init = false;
     int passed_fd = -1;
     const char *e;
 #ifdef HAVE_FORK
     int daemon_pipe[2] = { -1, -1 };
+    int daemon_pipe2[2] = { -1, -1 };
 #endif
 #ifdef OS_IS_WIN32
     pa_time_event *win32_timer;
     struct timeval win32_tv;
 #endif
     int autospawn_fd = -1;
-    pa_bool_t autospawn_locked = FALSE;
+    bool autospawn_locked = false;
 #ifdef HAVE_DBUS
     pa_dbusobj_server_lookup *server_lookup = NULL; /* /org/pulseaudio/server_lookup */
     pa_dbus_connection *lookup_service_bus = NULL; /* Always the user bus. */
     pa_dbus_connection *server_bus = NULL; /* The bus where we reserve org.pulseaudio.Server, either the user or the system bus. */
-    pa_bool_t start_server;
+    bool start_server;
 #endif
 
     pa_log_set_ident("pulseaudio");
@@ -480,8 +499,14 @@ int main(int argc, char *argv[]) {
         goto finish;
     }
 
+    if (conf->log_target)
+        pa_log_set_target(conf->log_target);
+    else {
+        pa_log_target target = { .type = PA_LOG_STDERR, .file = NULL };
+        pa_log_set_target(&target);
+    }
+
     pa_log_set_level(conf->log_level);
-    pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target);
     if (conf->log_meta)
         pa_log_set_flags(PA_LOG_PRINT_META, PA_LOG_SET);
     if (conf->log_time)
@@ -497,10 +522,10 @@ int main(int argc, char *argv[]) {
             break;
         case PA_SERVER_TYPE_USER:
         case PA_SERVER_TYPE_NONE:
-            conf->system_instance = FALSE;
+            conf->system_instance = false;
             break;
         case PA_SERVER_TYPE_SYSTEM:
-            conf->system_instance = TRUE;
+            conf->system_instance = true;
             break;
         default:
             pa_assert_not_reached();
@@ -510,13 +535,13 @@ int main(int argc, char *argv[]) {
 
     if (!start_server && conf->local_server_type == PA_SERVER_TYPE_SYSTEM) {
         pa_log_notice(_("System mode refused for non-root user. Only starting the D-Bus server lookup service."));
-        conf->system_instance = FALSE;
+        conf->system_instance = false;
     }
 #endif
 
     LTDL_SET_PRELOADED_SYMBOLS();
     pa_ltdl_init();
-    ltdl_init = TRUE;
+    ltdl_init = true;
 
     if (conf->dl_search_path)
         lt_dlsetsearchpath(conf->dl_search_path);
@@ -537,6 +562,12 @@ int main(int argc, char *argv[]) {
             goto finish;
 
         case PA_CMD_DUMP_CONF: {
+
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             s = pa_daemon_conf_dump(conf);
             fputs(s, stdout);
             pa_xfree(s);
@@ -547,6 +578,11 @@ int main(int argc, char *argv[]) {
         case PA_CMD_DUMP_RESAMPLE_METHODS: {
             int i;
 
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             for (i = 0; i < PA_RESAMPLER_MAX; i++)
                 if (pa_resample_method_supported(i))
                     printf("%s\n", pa_resample_method_to_string(i));
@@ -561,6 +597,12 @@ int main(int argc, char *argv[]) {
             goto finish;
 
         case PA_CMD_VERSION :
+
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             printf(PACKAGE_NAME" "PACKAGE_VERSION"\n");
             retval = 0;
             goto finish;
@@ -568,6 +610,11 @@ int main(int argc, char *argv[]) {
         case PA_CMD_CHECK: {
             pid_t pid;
 
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             if (pa_pid_file_check_running(&pid, "pulseaudio") < 0)
                 pa_log_info(_("Daemon not running"));
             else {
@@ -580,6 +627,11 @@ int main(int argc, char *argv[]) {
         }
         case PA_CMD_KILL:
 
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0)
                 pa_log(_("Failed to kill daemon: %s"), pa_cstrerror(errno));
             else
@@ -589,6 +641,11 @@ int main(int argc, char *argv[]) {
 
         case PA_CMD_CLEANUP_SHM:
 
+            if (d < argc) {
+                pa_log("Too many arguments.\n");
+                goto finish;
+            }
+
             if (pa_shm_cleanup() >= 0)
                 retval = 0;
 
@@ -598,6 +655,12 @@ int main(int argc, char *argv[]) {
             pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START);
     }
 
+    if (d < argc) {
+        pa_log("Too many arguments.\n");
+        goto finish;
+    }
+
+#ifdef HAVE_GETUID
     if (getuid() == 0 && !conf->system_instance)
         pa_log_warn(_("This program is not intended to be run as root (unless --system is specified)."));
 #ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */
@@ -606,12 +669,59 @@ int main(int argc, char *argv[]) {
         goto finish;
     }
 #endif
+#endif  /* HAVE_GETUID */
 
     if (conf->cmd == PA_CMD_START && conf->system_instance) {
         pa_log(_("--start not supported for system instances."));
         goto finish;
     }
 
+    if (conf->cmd == PA_CMD_START && (configured_address = check_configured_address())) {
+        /* There is an server address in our config, but where did it come from?
+         * By default a standard X11 login will load module-x11-publish which will
+         * inject PULSE_SERVER X11 property. If the PA daemon crashes, we will end
+         * up hitting this code path. So we have to check to see if our configured_address
+         * is the same as the value that would go into this property so that we can
+         * recover (i.e. autospawn) from a crash.
+         */
+        char *ufn;
+        bool start_anyway = false;
+
+        if ((ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET))) {
+            char *id;
+
+            if ((id = pa_machine_id())) {
+                pa_strlist *server_list;
+                char formatted_ufn[256];
+
+                pa_snprintf(formatted_ufn, sizeof(formatted_ufn), "{%s}unix:%s", id, ufn);
+                pa_xfree(id);
+
+                if ((server_list = pa_strlist_parse(configured_address))) {
+                    char *u = NULL;
+
+                    /* We only need to check the first server */
+                    server_list = pa_strlist_pop(server_list, &u);
+                    pa_strlist_free(server_list);
+
+                    start_anyway = (u && pa_streq(formatted_ufn, u));
+                    pa_xfree(u);
+                }
+            }
+            pa_xfree(ufn);
+        }
+
+        if (!start_anyway) {
+            pa_log_notice(_("User-configured server at %s, refusing to start/autospawn."), configured_address);
+            pa_xfree(configured_address);
+            retval = 0;
+            goto finish;
+        }
+
+        pa_log_notice(_("User-configured server at %s, which appears to be local. Probing deeper."), configured_address);
+        pa_xfree(configured_address);
+    }
+
     if (conf->system_instance && !conf->disallow_exit)
         pa_log_warn(_("Running in system mode, but --disallow-exit not set!"));
 
@@ -620,7 +730,7 @@ int main(int argc, char *argv[]) {
 
     if (conf->system_instance && !conf->disable_shm) {
         pa_log_notice(_("Running in system mode, forcibly disabling SHM mode!"));
-        conf->disable_shm = TRUE;
+        conf->disable_shm = true;
     }
 
     if (conf->system_instance && conf->exit_idle_time >= 0) {
@@ -638,16 +748,18 @@ int main(int argc, char *argv[]) {
             goto finish;
         }
 
-        if ((pa_autospawn_lock_acquire(TRUE) < 0)) {
+        if ((pa_autospawn_lock_acquire(true) < 0)) {
             pa_log("Failed to acquire autospawn lock");
             goto finish;
         }
 
-        autospawn_locked = TRUE;
+        autospawn_locked = true;
     }
 
     if (conf->daemonize) {
+#ifdef HAVE_FORK
         pid_t child;
+#endif
 
         if (pa_stdio_acquire() < 0) {
             pa_log(_("Failed to acquire stdio."));
@@ -662,6 +774,7 @@ int main(int argc, char *argv[]) {
 
         if ((child = fork()) < 0) {
             pa_log(_("fork() failed: %s"), pa_cstrerror(errno));
+            pa_close_pipe(daemon_pipe);
             goto finish;
         }
 
@@ -693,9 +806,9 @@ int main(int argc, char *argv[]) {
              * to close it in the child */
 
             pa_autospawn_lock_release();
-            pa_autospawn_lock_done(TRUE);
+            pa_autospawn_lock_done(true);
 
-            autospawn_locked = FALSE;
+            autospawn_locked = false;
             autospawn_fd = -1;
         }
 
@@ -703,8 +816,14 @@ int main(int argc, char *argv[]) {
         daemon_pipe[0] = -1;
 #endif
 
-        if (conf->auto_log_target)
-            pa_log_set_target(PA_LOG_SYSLOG);
+        if (!conf->log_target) {
+#ifdef HAVE_JOURNAL
+            pa_log_target target = { .type = PA_LOG_JOURNAL, .file = NULL };
+#else
+            pa_log_target target = { .type = PA_LOG_SYSLOG, .file = NULL };
+#endif
+            pa_log_set_target(&target);
+        }
 
 #ifdef HAVE_SETSID
         if (setsid() < 0) {
@@ -713,21 +832,54 @@ int main(int argc, char *argv[]) {
         }
 #endif
 
+#ifdef HAVE_FORK
         /* We now are a session and process group leader. Let's fork
          * again and let the father die, so that we'll become a
          * process that can never acquire a TTY again, in a session and
          * process group without leader */
 
-#ifdef HAVE_FORK
+        if (pipe(daemon_pipe2) < 0) {
+            pa_log(_("pipe() failed: %s"), pa_cstrerror(errno));
+            goto finish;
+        }
+
         if ((child = fork()) < 0) {
             pa_log(_("fork() failed: %s"), pa_cstrerror(errno));
+            pa_close_pipe(daemon_pipe2);
             goto finish;
         }
 
         if (child != 0) {
-            retval = 0;
+            ssize_t n;
+            /* Father */
+
+            pa_assert_se(pa_close(daemon_pipe2[1]) == 0);
+            daemon_pipe2[1] = -1;
+
+            if ((n = pa_loop_read(daemon_pipe2[0], &retval, sizeof(retval), NULL)) != sizeof(retval)) {
+
+                if (n < 0)
+                    pa_log(_("read() failed: %s"), pa_cstrerror(errno));
+
+                retval = 1;
+            }
+
+            /* We now have to take care of signalling the first fork with
+             * the return value we've received from this fork... */
+            pa_assert(daemon_pipe[1] >= 0);
+
+            pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+            pa_close(daemon_pipe[1]);
+            daemon_pipe[1] = -1;
+
             goto finish;
         }
+
+        pa_assert_se(pa_close(daemon_pipe2[0]) == 0);
+        daemon_pipe2[0] = -1;
+
+        /* We no longer need the (first) daemon_pipe as it's handled in our child above */
+        pa_close_pipe(daemon_pipe);
 #endif
 
 #ifdef SIGTTOU
@@ -752,7 +904,8 @@ int main(int argc, char *argv[]) {
 #endif
     pa_rtclock_hrtimer_enable();
 
-    pa_raise_priority(conf->nice_level);
+    if (conf->high_priority)
+        pa_raise_priority(conf->nice_level);
 
     if (conf->system_instance)
         if (change_user() < 0)
@@ -844,7 +997,7 @@ int main(int argc, char *argv[]) {
             goto finish;
         }
 
-        valid_pid_file = TRUE;
+        valid_pid_file = true;
     }
 
     pa_disable_sigpipe();
@@ -855,11 +1008,11 @@ int main(int argc, char *argv[]) {
         pa_log_info(_("Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!"));
 
     if (conf->lock_memory) {
-#ifdef HAVE_SYS_MMAN_H
+#if defined(HAVE_SYS_MMAN_H) && !defined(__ANDROID__)
         if (mlockall(MCL_FUTURE) < 0)
             pa_log_warn("mlockall() failed: %s", pa_cstrerror(errno));
         else
-            pa_log_info("Sucessfully locked process into memory.");
+            pa_log_info("Successfully locked process into memory.");
 #else
         pa_log_warn("Memory locking requested but not supported on platform.");
 #endif
@@ -867,11 +1020,6 @@ int main(int argc, char *argv[]) {
 
     pa_memtrap_install();
 
-    if (!getenv("PULSE_NO_SIMD")) {
-        pa_cpu_init_x86();
-        pa_cpu_init_arm();
-    }
-
     pa_assert_se(mainloop = pa_mainloop_new());
 
     if (!(c = pa_core_new(pa_mainloop_get_api(mainloop), !conf->disable_shm, conf->shm_size))) {
@@ -880,9 +1028,12 @@ int main(int argc, char *argv[]) {
     }
 
     c->default_sample_spec = conf->default_sample_spec;
+    c->alternate_sample_rate = conf->alternate_sample_rate;
     c->default_channel_map = conf->default_channel_map;
     c->default_n_fragments = conf->default_n_fragments;
     c->default_fragment_size_msec = conf->default_fragment_size_msec;
+    c->deferred_volume_safety_margin_usec = conf->deferred_volume_safety_margin_usec;
+    c->deferred_volume_extra_delay_usec = conf->deferred_volume_extra_delay_usec;
     c->exit_idle_time = conf->exit_idle_time;
     c->scache_idle_time = conf->scache_idle_time;
     c->resample_method = conf->resample_method;
@@ -890,6 +1041,7 @@ int main(int argc, char *argv[]) {
     c->realtime_scheduling = !!conf->realtime_scheduling;
     c->disable_remixing = !!conf->disable_remixing;
     c->disable_lfe_remixing = !!conf->disable_lfe_remixing;
+    c->deferred_volume = !!conf->deferred_volume;
     c->running_as_daemon = !!conf->daemonize;
     c->disallow_exit = conf->disallow_exit;
     c->flat_volumes = conf->flat_volumes;
@@ -897,6 +1049,15 @@ int main(int argc, char *argv[]) {
     c->server_type = conf->local_server_type;
 #endif
 
+    c->cpu_info.cpu_type = PA_CPU_UNDEFINED;
+    if (!getenv("PULSE_NO_SIMD")) {
+        if (pa_cpu_init_x86(&(c->cpu_info.flags.x86)))
+            c->cpu_info.cpu_type = PA_CPU_X86;
+        if (pa_cpu_init_arm(&(c->cpu_info.flags.arm)))
+            c->cpu_info.cpu_type = PA_CPU_ARM;
+        pa_cpu_init_orc(c->cpu_info);
+    }
+
     pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
     pa_signal_new(SIGINT, signal_callback, c);
     pa_signal_new(SIGTERM, signal_callback, c);
@@ -911,7 +1072,7 @@ int main(int argc, char *argv[]) {
 #endif
 
 #ifdef OS_IS_WIN32
-    win32_timer = pa_mainloop_get_api(mainloop)->rtclock_time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
+    win32_timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
 #endif
 
     if (!conf->no_cpu_limit)
@@ -920,6 +1081,8 @@ int main(int argc, char *argv[]) {
     buf = pa_strbuf_new();
 
 #ifdef HAVE_DBUS
+    pa_assert_se(dbus_threads_init_default());
+
     if (start_server) {
 #endif
         if (conf->load_default_script_file) {
@@ -952,7 +1115,7 @@ int main(int argc, char *argv[]) {
          * any modules to be loaded. We haven't loaded any so far, so one might
          * think there's no way to contact the server, but receiving certain
          * signals could still cause modules to load. */
-        conf->disallow_module_loading = TRUE;
+        conf->disallow_module_loading = true;
     }
 #endif
 
@@ -960,25 +1123,25 @@ int main(int argc, char *argv[]) {
      * from now on, if requested */
     c->disallow_module_loading = !!conf->disallow_module_loading;
 
-#ifdef HAVE_FORK
-    if (daemon_pipe[1] >= 0) {
-        int ok = 0;
-        pa_loop_write(daemon_pipe[1], &ok, sizeof(ok), NULL);
-        pa_close(daemon_pipe[1]);
-        daemon_pipe[1] = -1;
-    }
-#endif
-
 #ifdef HAVE_DBUS
     if (!conf->system_instance) {
-        if (!(server_lookup = pa_dbusobj_server_lookup_new(c)))
-            goto finish;
-        if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.PulseAudio1")))
-            goto finish;
+        if ((server_lookup = pa_dbusobj_server_lookup_new(c))) {
+            if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.PulseAudio1")))
+                goto finish;
+        }
     }
 
-    if (start_server && !(server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server")))
-        goto finish;
+    if (start_server)
+        server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server");
+#endif
+
+#ifdef HAVE_FORK
+    if (daemon_pipe2[1] >= 0) {
+        int ok = 0;
+        pa_loop_write(daemon_pipe2[1], &ok, sizeof(ok), NULL);
+        pa_close(daemon_pipe2[1]);
+        daemon_pipe2[1] = -1;
+    }
 #endif
 
     pa_log_info(_("Daemon startup complete."));
@@ -1003,15 +1166,20 @@ finish:
         if (autospawn_locked)
             pa_autospawn_lock_release();
 
-        pa_autospawn_lock_done(FALSE);
+        pa_autospawn_lock_done(false);
     }
 
 #ifdef OS_IS_WIN32
-    if (win32_timer)
+    if (mainloop && win32_timer)
         pa_mainloop_get_api(mainloop)->time_free(win32_timer);
 #endif
 
     if (c) {
+        /* Ensure all the modules/samples are unloaded when the core is still ref'ed,
+         * as unlink callback hooks in modules may need the core to be ref'ed */
+        pa_module_unload_all(c);
+        pa_scache_free_all(c);
+
         pa_core_unref(c);
         pa_log_info(_("Daemon terminated."));
     }
@@ -1022,9 +1190,14 @@ finish:
     pa_signal_done();
 
 #ifdef HAVE_FORK
+    /* If we have daemon_pipe[1] still open, this means we've failed after
+     * the first fork, but before the second. Therefore just write to it. */
     if (daemon_pipe[1] >= 0)
         pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+    else if (daemon_pipe2[1] >= 0)
+        pa_loop_write(daemon_pipe2[1], &retval, sizeof(retval), NULL);
 
+    pa_close_pipe(daemon_pipe2);
     pa_close_pipe(daemon_pipe);
 #endif