X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/27b8cd783c2aedb23af8f88fc88632d5c4f387fd..0a583fe0c330d167f52784585afffdd8065a92cd:/src/daemon/main.c diff --git a/src/daemon/main.c b/src/daemon/main.c index 8521e720..02a8ea64 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -33,22 +33,15 @@ #include #include #include -#include #include #include #include #include -#include - #ifdef HAVE_SYS_MMAN_H #include #endif -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - #ifdef HAVE_PWD_H #include #endif @@ -65,18 +58,22 @@ #include #endif +#include +#ifdef HAVE_X11 +#include +#endif #include #include #include #include -#include +#include #include -#include +#include #include #include +#include #include -#include #include #include #include @@ -84,17 +81,17 @@ #include #include #include -#include #include #include -#include -#include -#include #include #include +#include #ifdef HAVE_DBUS #include #endif +#include +#include +#include #include "cmdline.h" #include "cpulimit.h" @@ -102,6 +99,7 @@ #include "dumpmodules.h" #include "caps.h" #include "ltdl-bind-now.h" +#include "server-lookup.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -132,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 @@ -201,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; } @@ -253,17 +251,24 @@ 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); 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; } @@ -337,34 +342,50 @@ 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(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); @@ -379,22 +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_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"); @@ -411,23 +437,31 @@ int main(int argc, char *argv[]) { 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 @@ -465,17 +499,49 @@ 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) 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); @@ -496,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); @@ -506,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)); @@ -520,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; @@ -527,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 { @@ -539,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 @@ -548,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; @@ -557,18 +655,73 @@ 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. */ 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!")); @@ -577,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) { @@ -595,17 +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; - int tty_fd; +#endif if (pa_stdio_acquire() < 0) { pa_log(_("Failed to acquire stdio.")); @@ -614,12 +768,13 @@ int main(int argc, char *argv[]) { #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; } @@ -651,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; } @@ -661,26 +816,70 @@ 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 - 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 @@ -693,15 +892,10 @@ int main(int argc, char *argv[]) { 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); @@ -710,13 +904,14 @@ 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) 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); @@ -738,6 +933,8 @@ int main(int argc, char *argv[]) { 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 @@ -774,6 +971,8 @@ int main(int argc, char *argv[]) { pa_log_info(_("Using state directory %s."), s); pa_xfree(s); + pa_log_info(_("Using modules directory %s."), conf->dl_search_path); + pa_log_info(_("Running in system mode: %s"), pa_yes_no(pa_in_system_mode())); if (pa_in_system_mode()) @@ -798,7 +997,7 @@ int main(int argc, char *argv[]) { goto finish; } - valid_pid_file = TRUE; + valid_pid_file = true; } pa_disable_sigpipe(); @@ -809,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 @@ -829,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; @@ -839,9 +1041,22 @@ 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; +#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); @@ -857,57 +1072,78 @@ 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 - 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; @@ -918,23 +1154,32 @@ int main(int argc, char *argv[]) { 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.")); } @@ -945,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 @@ -960,6 +1210,9 @@ finish: 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