#include <stddef.h>
#include <ltdl.h>
#include <limits.h>
-#include <fcntl.h>
#include <unistd.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <liboil/liboil.h>
-
#ifdef HAVE_SYS_MMAN_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"
#include "dumpmodules.h"
#include "caps.h"
#include "ltdl-bind-now.h"
+#include "server-lookup.h"
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
}
pa_timeval_add(pa_gettimeofday(&tvnext), 100000);
- a->rtclock_time_restart(e, &tvnext);
+ a->time_restart(e, &tvnext);
}
#endif
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;
}
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);
pa_set_env("HOME", PA_SYSTEM_RUNTIME_PATH);
/* Relevant for pa_runtime_path() */
- pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH);
- pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH);
- pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH);
+ if (!getenv("PULSE_RUNTIME_PATH"))
+ pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH);
- pa_log_info(_("Successfully dropped root privileges."));
+ if (!getenv("PULSE_CONFIG_PATH"))
+ pa_set_env("PULSE_CONFIG_PATH", PA_SYSTEM_CONFIG_PATH);
+
+ if (!getenv("PULSE_STATE_PATH"))
+ pa_set_env("PULSE_STATE_PATH", PA_SYSTEM_STATE_PATH);
+
+ pa_log_info(_("Successfully changed user to \"" PA_SYSTEM_USER "\"."));
return 0;
}
}
#endif
+static char *check_configured_address(void) {
+ char *default_server = NULL;
+ pa_client_conf *c = pa_client_conf_new();
+
+ pa_client_conf_load(c, NULL);
+#ifdef HAVE_X11
+ pa_client_conf_from_x11(c, NULL);
+#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(pa_core *c) {
+static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
DBusError error;
pa_dbus_connection *conn;
dbus_error_init(&error);
- if (!(conn = pa_dbus_bus_get(c, pa_in_system_mode() ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
+ if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) {
pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
goto fail;
}
- if (dbus_bus_request_name(pa_dbus_connection_get(conn), "org.pulseaudio.Server", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
- pa_log_debug("Got org.pulseaudio.Server!");
+ if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+ pa_log_debug("Got %s!", name);
return conn;
}
if (dbus_error_is_set(&error))
- pa_log_warn("Failed to acquire org.pulseaudio.Server: %s: %s", error.name, error.message);
+ pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
else
- pa_log_warn("D-Bus name org.pulseaudio.Server already taken. Weird shit!");
+ 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 org.pulseaudio.Server is already
- * taken. */
+ * ignore mostly the case that a name is already taken. */
fail:
-
if (conn)
pa_dbus_connection_unref(conn);
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_dbus_connection *dbus = NULL;
+ 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. */
+ bool start_server;
#endif
pa_log_set_ident("pulseaudio");
if (!getenv("LD_BIND_NOW")) {
char *rp;
+ char *canonical_rp;
/* We have to execute ourselves, because the libc caches the
* value of $LD_BIND_NOW on initialization. */
pa_set_env("LD_BIND_NOW", "1");
- if ((rp = pa_readlink("/proc/self/exe"))) {
+ if ((canonical_rp = pa_realpath(PA_BINARY))) {
- if (pa_streq(rp, PA_BINARY))
- pa_assert_se(execv(rp, argv) == 0);
- else
- pa_log_warn("/proc/self/exe does not point to " PA_BINARY ", cannot self execute. Are you playing games?");
+ if ((rp = pa_readlink("/proc/self/exe"))) {
+
+ if (pa_streq(rp, canonical_rp))
+ pa_assert_se(execv(rp, argv) == 0);
+ else
+ pa_log_warn("/proc/self/exe does not point to %s, cannot self execute. Are you playing games?", canonical_rp);
+
+ pa_xfree(rp);
- pa_xfree(rp);
+ } else
+ pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?");
+
+ pa_xfree(canonical_rp);
} else
- pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?");
+ pa_log_warn("Couldn't canonicalize binary path, cannot self execute.");
}
#endif
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)
pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET);
pa_log_set_show_backtrace(conf->log_backtrace);
+#ifdef HAVE_DBUS
+ /* conf->system_instance and conf->local_server_type control almost the
+ * same thing; make them agree about what is requested. */
+ switch (conf->local_server_type) {
+ case PA_SERVER_TYPE_UNSET:
+ conf->local_server_type = conf->system_instance ? PA_SERVER_TYPE_SYSTEM : PA_SERVER_TYPE_USER;
+ break;
+ case PA_SERVER_TYPE_USER:
+ case PA_SERVER_TYPE_NONE:
+ conf->system_instance = false;
+ break;
+ case PA_SERVER_TYPE_SYSTEM:
+ conf->system_instance = true;
+ break;
+ default:
+ pa_assert_not_reached();
+ }
+
+ start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (getuid() == 0 && conf->local_server_type == PA_SERVER_TYPE_SYSTEM);
+
+ 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;
+ }
+#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);
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);
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));
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;
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 {
}
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
case PA_CMD_CLEANUP_SHM:
+ if (d < argc) {
+ pa_log("Too many arguments.\n");
+ goto finish;
+ }
+
if (pa_shm_cleanup() >= 0)
retval = 0;
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. */
else if (getuid() != 0 && conf->system_instance) {
pa_log(_("Root privileges required."));
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!"));
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) {
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;
- int tty_fd;
+#endif
if (pa_stdio_acquire() < 0) {
pa_log(_("Failed to acquire stdio."));
#ifdef HAVE_FORK
if (pipe(daemon_pipe) < 0) {
- pa_log(_("pipe failed: %s"), pa_cstrerror(errno));
+ 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_pipe);
goto finish;
}
* 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;
}
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
- setsid();
-#endif
-#ifdef HAVE_SETPGID
- setpgid(0,0);
+ if (setsid() < 0) {
+ pa_log(_("setsid() failed: %s"), pa_cstrerror(errno));
+ goto finish;
+ }
#endif
-#ifndef OS_IS_WIN32
- pa_close(0);
- pa_close(1);
- pa_close(2);
+#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 */
- pa_assert_se(open("/dev/null", O_RDONLY) == 0);
- pa_assert_se(open("/dev/null", O_WRONLY) == 1);
- pa_assert_se(open("/dev/null", O_WRONLY) == 2);
-#else
- FreeConsole();
+ 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) {
+ 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
signal(SIGTSTP, SIG_IGN);
#endif
-#ifdef TIOCNOTTY
- if ((tty_fd = open("/dev/tty", O_RDWR)) >= 0) {
- ioctl(tty_fd, TIOCNOTTY, (char*) 0);
- pa_assert_se(pa_close(tty_fd) == 0);
- }
-#endif
+ pa_nullify_stdfds();
}
- pa_set_env("PULSE_INTERNAL", "1");
+ pa_set_env_and_record("PULSE_INTERNAL", "1");
pa_assert_se(chdir("/") == 0);
umask(0022);
#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)
goto finish;
- pa_set_env("PULSE_SYSTEM", conf->system_instance ? "1" : "0");
+ pa_set_env_and_record("PULSE_SYSTEM", conf->system_instance ? "1" : "0");
pa_log_info(_("This is PulseAudio %s"), PACKAGE_VERSION);
pa_log_debug(_("Compilation host: %s"), CANONICAL_HOST);
pa_log_debug(_("Running in valgrind mode: %s"), pa_yes_no(pa_in_valgrind()));
+ pa_log_debug(_("Running in VM: %s"), pa_yes_no(pa_running_in_vm()));
+
#ifdef __OPTIMIZE__
pa_log_debug(_("Optimized build: yes"));
#else
goto finish;
}
- valid_pid_file = TRUE;
+ valid_pid_file = true;
}
pa_disable_sigpipe();
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
}
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;
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;
+#ifdef HAVE_DBUS
+ 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);
#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
- oil_init();
-
if (!conf->no_cpu_limit)
pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
buf = pa_strbuf_new();
- if (conf->load_default_script_file) {
- FILE *f;
- if ((f = pa_daemon_conf_open_default_script_file(conf))) {
- r = pa_cli_command_execute_file_stream(c, f, buf, &conf->fail);
- fclose(f);
+#ifdef HAVE_DBUS
+ pa_assert_se(dbus_threads_init_default());
+
+ if (start_server) {
+#endif
+ if (conf->load_default_script_file) {
+ FILE *f;
+
+ if ((f = pa_daemon_conf_open_default_script_file(conf))) {
+ r = pa_cli_command_execute_file_stream(c, f, buf, &conf->fail);
+ fclose(f);
+ }
}
- }
- if (r >= 0)
- r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
+ if (r >= 0)
+ r = pa_cli_command_execute(c, conf->script_commands, buf, &conf->fail);
- pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
- pa_xfree(s);
+ pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
+ pa_xfree(s);
+
+ if (r < 0 && conf->fail) {
+ pa_log(_("Failed to initialize daemon."));
+ goto finish;
+ }
+
+ if (!c->modules || pa_idxset_size(c->modules) == 0) {
+ pa_log(_("Daemon startup without any loaded modules, refusing to work."));
+ goto finish;
+ }
+#ifdef HAVE_DBUS
+ } else {
+ /* When we just provide the D-Bus server lookup service, we don't want
+ * 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;
+ }
+#endif
/* We completed the initial module loading, so let's disable it
* from now on, if requested */
c->disallow_module_loading = !!conf->disallow_module_loading;
- if (r < 0 && conf->fail) {
- pa_log(_("Failed to initialize daemon."));
- goto finish;
+#ifdef HAVE_DBUS
+ if (!conf->system_instance) {
+ 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 (!c->modules || pa_idxset_size(c->modules) == 0) {
- pa_log(_("Daemon startup without any loaded modules, refusing to work."));
- 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_pipe[1] >= 0) {
+ if (daemon_pipe2[1] >= 0) {
int ok = 0;
- pa_loop_write(daemon_pipe[1], &ok, sizeof(ok), NULL);
- pa_close(daemon_pipe[1]);
- daemon_pipe[1] = -1;
+ pa_loop_write(daemon_pipe2[1], &ok, sizeof(ok), NULL);
+ pa_close(daemon_pipe2[1]);
+ daemon_pipe2[1] = -1;
}
#endif
-#ifdef HAVE_DBUS
- dbus = register_dbus(c);
-#endif
-
pa_log_info(_("Daemon startup complete."));
retval = 0;
finish:
#ifdef HAVE_DBUS
- if (dbus)
- pa_dbus_connection_unref(dbus);
+ if (server_bus)
+ pa_dbus_connection_unref(server_bus);
+ if (lookup_service_bus)
+ pa_dbus_connection_unref(lookup_service_bus);
+ if (server_lookup)
+ pa_dbusobj_server_lookup_free(server_lookup);
#endif
if (autospawn_fd >= 0) {
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."));
}
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
if (valid_pid_file)
pa_pid_file_remove();
+ /* This has no real purpose except making things valgrind-clean */
+ pa_unset_env_recorded();
+
#ifdef OS_IS_WIN32
WSACleanup();
#endif