diff options
Diffstat (limited to 'src/daemon')
| -rw-r--r-- | src/daemon/.gitignore | 1 | ||||
| l--------- | src/daemon/Makefile | 1 | ||||
| -rw-r--r-- | src/daemon/caps.c | 113 | ||||
| -rw-r--r-- | src/daemon/caps.h | 3 | ||||
| -rw-r--r-- | src/daemon/cmdline.c | 23 | ||||
| -rw-r--r-- | src/daemon/cpulimit.c | 16 | ||||
| -rw-r--r-- | src/daemon/daemon-conf.c | 160 | ||||
| -rw-r--r-- | src/daemon/daemon-conf.h | 9 | ||||
| -rw-r--r-- | src/daemon/daemon.conf.in | 33 | ||||
| -rwxr-xr-x | src/daemon/default.pa.in | 59 | ||||
| -rw-r--r-- | src/daemon/default.pa.win32 | 43 | ||||
| -rw-r--r-- | src/daemon/dumpmodules.c | 3 | ||||
| -rwxr-xr-x | src/daemon/esdcompat.in | 2 | ||||
| -rw-r--r-- | src/daemon/ltdl-bind-now.c | 4 | ||||
| -rw-r--r-- | src/daemon/main.c | 606 | ||||
| -rw-r--r-- | src/daemon/org.pulseaudio.policy.in | 50 | ||||
| -rw-r--r-- | src/daemon/polkit.c | 172 | ||||
| -rw-r--r-- | src/daemon/pulseaudio-kde.desktop.in | 11 | ||||
| -rw-r--r-- | src/daemon/pulseaudio-system.conf | 37 | ||||
| -rw-r--r-- | src/daemon/server-lookup.c | 522 | ||||
| -rw-r--r-- | src/daemon/server-lookup.h (renamed from src/daemon/polkit.h) | 21 | ||||
| -rwxr-xr-x | src/daemon/start-pulseaudio-kde.in | 30 | ||||
| -rwxr-xr-x | src/daemon/start-pulseaudio-x11.in | 2 | ||||
| -rwxr-xr-x | src/daemon/system.pa.in | 9 |
24 files changed, 1225 insertions, 705 deletions
diff --git a/src/daemon/.gitignore b/src/daemon/.gitignore index 0efa55ba..54e4299b 100644 --- a/src/daemon/.gitignore +++ b/src/daemon/.gitignore @@ -1,2 +1,3 @@ org.pulseaudio.policy pulseaudio.desktop +pulseaudio-kde.desktop diff --git a/src/daemon/Makefile b/src/daemon/Makefile deleted file mode 120000 index c110232d..00000000 --- a/src/daemon/Makefile +++ /dev/null @@ -1 +0,0 @@ -../pulse/Makefile
\ No newline at end of file diff --git a/src/daemon/caps.c b/src/daemon/caps.c index d2ae8d0e..74ccb1c8 100644 --- a/src/daemon/caps.c +++ b/src/daemon/caps.c @@ -26,19 +26,17 @@ #include <unistd.h> #include <errno.h> -#include <string.h> #include <sys/types.h> #include <pulse/i18n.h> #include <pulsecore/macro.h> -#include <pulsecore/core-error.h> #include <pulsecore/log.h> -#include <pulsecore/core-util.h> #ifdef HAVE_SYS_CAPABILITY_H #include <sys/capability.h> #endif + #ifdef HAVE_SYS_PRCTL_H #include <sys/prctl.h> #endif @@ -51,112 +49,47 @@ int setresgid(gid_t r, gid_t e, gid_t s); int setresuid(uid_t r, uid_t e, uid_t s); #endif -#ifdef HAVE_GETUID - /* Drop root rights when called SUID root */ void pa_drop_root(void) { - uid_t uid = getuid(); - if (uid == 0 || geteuid() != 0) - return; +#ifdef HAVE_GETUID + uid_t uid; + gid_t gid; - pa_log_info(_("Dropping root privileges.")); + pa_log_debug(_("Cleaning up privileges.")); + uid = getuid(); + gid = getgid(); #if defined(HAVE_SETRESUID) pa_assert_se(setresuid(uid, uid, uid) >= 0); + pa_assert_se(setresgid(gid, gid, gid) >= 0); #elif defined(HAVE_SETREUID) pa_assert_se(setreuid(uid, uid) >= 0); + pa_assert_se(setregid(gid, gid) >= 0); #else pa_assert_se(setuid(uid) >= 0); pa_assert_se(seteuid(uid) >= 0); + pa_assert_se(setgid(gid) >= 0); + pa_assert_se(setegid(gid) >= 0); #endif pa_assert_se(getuid() == uid); pa_assert_se(geteuid() == uid); -} - -#else - -void pa_drop_root(void) { -} - -#endif - -#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H) - -/* Limit permitted capabilities set to CAPSYS_NICE */ -void pa_limit_caps(void) { - cap_t caps; - cap_value_t nice_cap = CAP_SYS_NICE; - - pa_assert_se(caps = cap_init()); - pa_assert_se(cap_clear(caps) == 0); - pa_assert_se(cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET) == 0); - pa_assert_se(cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET) == 0); - - if (cap_set_proc(caps) < 0) - /* Hmm, so we couldn't limit our caps, which probably means we - * hadn't any in the first place, so let's just make sure of - * that */ - pa_drop_caps(); - else - pa_log_info(_("Limited capabilities successfully to CAP_SYS_NICE.")); - - pa_assert_se(cap_free(caps) == 0); - - pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0); -} - -/* Drop all capabilities, effectively becoming a normal user */ -void pa_drop_caps(void) { - cap_t caps; - -#ifndef __OPTIMIZE__ - /* Valgrind doesn't not know set_caps, so we bypass it here -- but - * only in development builds.*/ - - if (pa_in_valgrind() && !pa_have_caps()) - return; + pa_assert_se(getgid() == gid); + pa_assert_se(getegid() == gid); #endif +#ifdef HAVE_SYS_PRCTL_H pa_assert_se(prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0); - - pa_assert_se(caps = cap_init()); - pa_assert_se(cap_clear(caps) == 0); - pa_assert_se(cap_set_proc(caps) == 0); - pa_assert_se(cap_free(caps) == 0); - - pa_assert_se(!pa_have_caps()); -} - -pa_bool_t pa_have_caps(void) { - cap_t caps; - cap_flag_value_t flag = CAP_CLEAR; - -#ifdef __OPTIMIZE__ - pa_assert_se(caps = cap_get_proc()); -#else - if (!(caps = cap_get_proc())) - return FALSE; #endif - pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0); - pa_assert_se(cap_free(caps) == 0); - - return flag == CAP_SET; -} - -#else - -/* NOOPs in case capabilities are not available. */ -void pa_limit_caps(void) { -} - -void pa_drop_caps(void) { - pa_drop_root(); -} - -pa_bool_t pa_have_caps(void) { - return FALSE; -} +#ifdef HAVE_SYS_CAPABILITY_H + if (uid != 0) { + cap_t caps; + pa_assert_se(caps = cap_init()); + pa_assert_se(cap_clear(caps) == 0); + pa_assert_se(cap_set_proc(caps) == 0); + pa_assert_se(cap_free(caps) == 0); + } #endif +} diff --git a/src/daemon/caps.h b/src/daemon/caps.h index 94241a9a..5d0ee62e 100644 --- a/src/daemon/caps.h +++ b/src/daemon/caps.h @@ -25,8 +25,5 @@ #include <pulsecore/macro.h> void pa_drop_root(void); -void pa_drop_caps(void); -void pa_limit_caps(void); -pa_bool_t pa_have_caps(void); #endif diff --git a/src/daemon/cmdline.c b/src/daemon/cmdline.c index d78089e1..ec37d46b 100644 --- a/src/daemon/cmdline.c +++ b/src/daemon/cmdline.c @@ -23,14 +23,13 @@ #include <config.h> #endif -#include <string.h> #include <stdlib.h> #include <stdio.h> #include <getopt.h> -#include <sys/stat.h> #include <pulse/xmalloc.h> #include <pulse/i18n.h> +#include <pulse/util.h> #include <pulsecore/core-util.h> #include <pulsecore/strbuf.h> @@ -109,15 +108,8 @@ static const struct option long_options[] = { }; void pa_cmdline_help(const char *argv0) { - const char *e; - pa_assert(argv0); - if ((e = strrchr(argv0, '/'))) - e++; - else - e = argv0; - printf(_("%s [options]\n\n" "COMMANDS:\n" " -h, --help Show this help\n" @@ -151,7 +143,8 @@ void pa_cmdline_help(const char *argv0) { " this time passed\n" " --log-level[=LEVEL] Increase or set verbosity level\n" " -v Increase the verbosity level\n" - " --log-target={auto,syslog,stderr} Specify the log target\n" + " --log-target={auto,syslog,stderr,file:PATH}\n" + " Specify the log target\n" " --log-meta[=BOOL] Include code location in log messages\n" " --log-time[=BOOL] Include timestamps in log messages\n" " --log-backtrace=FRAMES Include a backtrace in log messages\n" @@ -172,7 +165,8 @@ void pa_cmdline_help(const char *argv0) { " -C Open a command line on the running TTY\n" " after startup\n\n" - " -n Don't load default script file\n"), e); + " -n Don't load default script file\n"), + pa_path_get_filename(argv0)); } int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) { @@ -323,7 +317,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d case ARG_LOG_TARGET: if (pa_daemon_conf_set_log_target(conf, optarg) < 0) { - pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto'.")); + pa_log(_("Invalid log target: use either 'syslog', 'stderr' or 'auto' or a valid file name 'file:<path>'.")); goto fail; } break; @@ -390,11 +384,6 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d pa_xfree(conf->script_commands); conf->script_commands = pa_strbuf_tostring_free(buf); - if (!conf->script_commands) { - pa_xfree(conf->script_commands); - conf->script_commands = NULL; - } - *d = optind; return 0; diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c index 45d6a0fb..3a972975 100644 --- a/src/daemon/cpulimit.c +++ b/src/daemon/cpulimit.c @@ -23,14 +23,13 @@ #include <config.h> #endif -#include <pulse/error.h> +#include <pulse/rtclock.h> #include <pulse/timeval.h> #include <pulsecore/core-util.h> #include <pulsecore/core-error.h> #include <pulsecore/log.h> #include <pulsecore/macro.h> -#include <pulsecore/rtclock.h> #include "cpulimit.h" @@ -39,7 +38,6 @@ #include <errno.h> #include <stdio.h> #include <string.h> -#include <sys/time.h> #include <unistd.h> #include <signal.h> @@ -85,7 +83,7 @@ static struct sigaction sigaction_prev; static pa_bool_t installed = FALSE; /* The current state of operation */ -static enum { +static enum { PHASE_IDLE, /* Normal state */ PHASE_SOFT /* After CPU overload has been detected */ } phase = PHASE_IDLE; @@ -125,7 +123,7 @@ static void signal_handler(int sig) { char t[256]; #endif - now = pa_rtclock_usec(); + now = pa_rtclock_now(); elapsed = now - last_time; #ifdef PRINT_CPU_LOAD @@ -139,7 +137,7 @@ static void signal_handler(int sig) { write_err("Soft CPU time limit exhausted, terminating.\n"); /* Try a soft cleanup */ - (void) write(the_pipe[1], &c, sizeof(c)); + (void) pa_write(the_pipe[1], &c, sizeof(c), NULL); phase = PHASE_SOFT; reset_cpu_time(CPUTIME_INTERVAL_HARD); @@ -184,18 +182,16 @@ int pa_cpu_limit_init(pa_mainloop_api *m) { pa_assert(the_pipe[1] == -1); pa_assert(!installed); - last_time = pa_rtclock_usec(); + last_time = pa_rtclock_now(); /* Prepare the main loop pipe */ - if (pipe(the_pipe) < 0) { + if (pa_pipe_cloexec(the_pipe) < 0) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); return -1; } pa_make_fd_nonblock(the_pipe[0]); pa_make_fd_nonblock(the_pipe[1]); - pa_make_fd_cloexec(the_pipe[0]); - pa_make_fd_cloexec(the_pipe[1]); api = m; io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c index ac6cc8aa..bb929091 100644 --- a/src/daemon/daemon-conf.c +++ b/src/daemon/daemon-conf.c @@ -28,11 +28,17 @@ #include <stdio.h> #include <string.h> #include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> + +#ifdef HAVE_SCHED_H #include <sched.h> +#endif #include <pulse/xmalloc.h> #include <pulse/timeval.h> #include <pulse/i18n.h> +#include <pulse/version.h> #include <pulsecore/core-error.h> #include <pulsecore/core-util.h> @@ -60,7 +66,7 @@ static const pa_daemon_conf default_conf = { .fail = TRUE, .high_priority = TRUE, .nice_level = -11, - .realtime_scheduling = FALSE, + .realtime_scheduling = TRUE, .realtime_priority = 5, /* Half of JACK's default rtprio */ .disallow_module_loading = FALSE, .disallow_exit = FALSE, @@ -83,10 +89,17 @@ static const pa_daemon_conf default_conf = { .config_file = NULL, .use_pid_file = TRUE, .system_instance = FALSE, - .no_cpu_limit = FALSE, +#ifdef HAVE_DBUS + .local_server_type = PA_SERVER_TYPE_UNSET, /* The actual default is _USER, but we have to detect when the user doesn't specify this option. */ +#endif + .no_cpu_limit = TRUE, .disable_shm = FALSE, + .lock_memory = FALSE, + .sync_volume = TRUE, .default_n_fragments = 4, .default_fragment_size_msec = 25, + .sync_volume_safety_margin_usec = 8000, + .sync_volume_extra_delay_usec = 0, .default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }, .default_channel_map = { .channels = 2, .map = { PA_CHANNEL_POSITION_LEFT, PA_CHANNEL_POSITION_RIGHT } }, .shm_size = 0 @@ -131,15 +144,30 @@ static const pa_daemon_conf default_conf = { #endif }; -pa_daemon_conf* pa_daemon_conf_new(void) { - pa_daemon_conf *c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); +pa_daemon_conf *pa_daemon_conf_new(void) { + pa_daemon_conf *c; + + c = pa_xnewdup(pa_daemon_conf, &default_conf, 1); + +#ifdef OS_IS_WIN32 + c->dl_search_path = pa_sprintf_malloc("%s" PA_PATH_SEP "lib" PA_PATH_SEP "pulse-%d.%d" PA_PATH_SEP "modules", + pa_win32_get_toplevel(NULL), PA_MAJOR, PA_MINOR); +#else + if (pa_run_from_build_tree()) { + pa_log_notice("Detected that we are run from the build tree, fixing search path."); + c->dl_search_path = pa_xstrdup(PA_BUILDDIR "/.libs/"); + } else + c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); +#endif - c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH); return c; } void pa_daemon_conf_free(pa_daemon_conf *c) { pa_assert(c); + + pa_log_set_fd(-1); + pa_xfree(c->script_commands); pa_xfree(c->dl_search_path); pa_xfree(c->default_script_file); @@ -159,6 +187,21 @@ int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string) { } else if (!strcmp(string, "stderr")) { c->auto_log_target = 0; c->log_target = PA_LOG_STDERR; + } else if (pa_startswith(string, "file:")) { + char file_path[512]; + int log_fd; + + pa_strlcpy(file_path, string + 5, sizeof(file_path)); + + /* Open target file with user rights */ + if ((log_fd = open(file_path, O_RDWR|O_TRUNC|O_CREAT, S_IRWXU)) >= 0) { + c->auto_log_target = 0; + c->log_target = PA_LOG_FD; + pa_log_set_fd(log_fd); + } else { + printf("Failed to open target file %s, error : %s\n", file_path, pa_cstrerror(errno)); + return -1; + } } else return -1; @@ -203,6 +246,22 @@ int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) { return 0; } +int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string) { + pa_assert(c); + pa_assert(string); + + if (!strcmp(string, "user")) + c->local_server_type = PA_SERVER_TYPE_USER; + else if (!strcmp(string, "system")) { + c->local_server_type = PA_SERVER_TYPE_SYSTEM; + } else if (!strcmp(string, "none")) { + c->local_server_type = PA_SERVER_TYPE_NONE; + } else + return -1; + + return 0; +} + static int parse_log_target(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; @@ -251,8 +310,8 @@ static int parse_resample_method(const char *filename, unsigned line, const char return 0; } -static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { #ifdef HAVE_SYS_RESOURCE_H +static int parse_rlimit(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { struct pa_rlimit *r = data; pa_assert(filename); @@ -273,12 +332,10 @@ static int parse_rlimit(const char *filename, unsigned line, const char *section r->is_set = k >= 0; r->value = k >= 0 ? (rlim_t) k : 0; } -#else - pa_log_warn(_("[%s:%u] rlimit not supported on this platform."), filename, line); -#endif return 0; } +#endif static int parse_sample_format(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { pa_daemon_conf *c = data; @@ -413,6 +470,10 @@ static int parse_nice_level(const char *filename, unsigned line, const char *sec } static int parse_rtprio(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { +#ifdef OS_IS_WIN32 + pa_log("[%s:%u] Realtime priority not available on win32.", filename, line); +#else +# ifdef HAVE_SCHED_H pa_daemon_conf *c = data; int32_t rtprio; @@ -427,9 +488,30 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section } c->realtime_priority = (int) rtprio; +# endif +#endif /* OS_IS_WIN32 */ + return 0; } +#ifdef HAVE_DBUS +static int parse_server_type(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) { + pa_daemon_conf *c = data; + + pa_assert(filename); + pa_assert(lvalue); + pa_assert(rvalue); + pa_assert(data); + + if (pa_daemon_conf_set_local_server_type(c, rvalue) < 0) { + pa_log(_("[%s:%u] Invalid server type '%s'."), filename, line, rvalue); + return -1; + } + + return 0; +} +#endif + int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { int r = -1; FILE *f = NULL; @@ -440,12 +522,21 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "high-priority", pa_config_parse_bool, &c->high_priority, NULL }, { "realtime-scheduling", pa_config_parse_bool, &c->realtime_scheduling, NULL }, { "disallow-module-loading", pa_config_parse_bool, &c->disallow_module_loading, NULL }, + { "allow-module-loading", pa_config_parse_not_bool, &c->disallow_module_loading, NULL }, { "disallow-exit", pa_config_parse_bool, &c->disallow_exit, NULL }, + { "allow-exit", pa_config_parse_not_bool, &c->disallow_exit, NULL }, { "use-pid-file", pa_config_parse_bool, &c->use_pid_file, NULL }, { "system-instance", pa_config_parse_bool, &c->system_instance, NULL }, +#ifdef HAVE_DBUS + { "local-server-type", parse_server_type, c, NULL }, +#endif { "no-cpu-limit", pa_config_parse_bool, &c->no_cpu_limit, NULL }, + { "cpu-limit", pa_config_parse_not_bool, &c->no_cpu_limit, NULL }, { "disable-shm", pa_config_parse_bool, &c->disable_shm, NULL }, + { "enable-shm", pa_config_parse_not_bool, &c->disable_shm, NULL }, { "flat-volumes", pa_config_parse_bool, &c->flat_volumes, NULL }, + { "lock-memory", pa_config_parse_bool, &c->lock_memory, NULL }, + { "enable-sync-volume", pa_config_parse_bool, &c->sync_volume, NULL }, { "exit-idle-time", pa_config_parse_int, &c->exit_idle_time, NULL }, { "scache-idle-time", pa_config_parse_int, &c->scache_idle_time, NULL }, { "realtime-priority", parse_rtprio, c, NULL }, @@ -461,9 +552,13 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { { "default-channel-map", parse_channel_map, &ci, NULL }, { "default-fragments", parse_fragments, c, NULL }, { "default-fragment-size-msec", parse_fragment_size_msec, c, NULL }, + { "sync-volume-safety-margin-usec", pa_config_parse_unsigned, &c->sync_volume_safety_margin_usec, NULL }, + { "sync-volume-extra-delay-usec", pa_config_parse_int, &c->sync_volume_extra_delay_usec, NULL }, { "nice-level", parse_nice_level, c, NULL }, { "disable-remixing", pa_config_parse_bool, &c->disable_remixing, NULL }, + { "enable-remixing", pa_config_parse_not_bool, &c->disable_remixing, NULL }, { "disable-lfe-remixing", pa_config_parse_bool, &c->disable_lfe_remixing, NULL }, + { "enable-lfe-remixing", pa_config_parse_not_bool, &c->disable_lfe_remixing, NULL }, { "load-default-script-file", pa_config_parse_bool, &c->load_default_script_file, NULL }, { "shm-size-bytes", pa_config_parse_size, &c->shm_size, NULL }, { "log-meta", pa_config_parse_bool, &c->log_meta, NULL }, @@ -515,7 +610,7 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) { c->config_file = NULL; f = filename ? - fopen(c->config_file = pa_xstrdup(filename), "r") : + pa_fopen_cloexec(c->config_file = pa_xstrdup(filename), "r") : pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file); if (!f && errno != ENOENT) { @@ -590,21 +685,29 @@ FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) { else f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file); } else - f = fopen(c->default_script_file, "r"); + f = pa_fopen_cloexec(c->default_script_file, "r"); return f; } +char *pa_daemon_conf_dump(pa_daemon_conf *c) { + static const char* const log_level_to_string[] = { + [PA_LOG_DEBUG] = "debug", + [PA_LOG_INFO] = "info", + [PA_LOG_NOTICE] = "notice", + [PA_LOG_WARN] = "warning", + [PA_LOG_ERROR] = "error" + }; -static const char* const log_level_to_string[] = { - [PA_LOG_DEBUG] = "debug", - [PA_LOG_INFO] = "info", - [PA_LOG_NOTICE] = "notice", - [PA_LOG_WARN] = "warning", - [PA_LOG_ERROR] = "error" -}; +#ifdef HAVE_DBUS + static const char* const server_type_to_string[] = { + [PA_SERVER_TYPE_UNSET] = "!!UNSET!!", + [PA_SERVER_TYPE_USER] = "user", + [PA_SERVER_TYPE_SYSTEM] = "system", + [PA_SERVER_TYPE_NONE] = "none" + }; +#endif -char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf *s; char cm[PA_CHANNEL_MAP_SNPRINT_MAX]; @@ -623,13 +726,18 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "nice-level = %i\n", c->nice_level); pa_strbuf_printf(s, "realtime-scheduling = %s\n", pa_yes_no(c->realtime_scheduling)); pa_strbuf_printf(s, "realtime-priority = %i\n", c->realtime_priority); - pa_strbuf_printf(s, "disallow-module-loading = %s\n", pa_yes_no(c->disallow_module_loading)); - pa_strbuf_printf(s, "disallow-exit = %s\n", pa_yes_no(c->disallow_exit)); + pa_strbuf_printf(s, "allow-module-loading = %s\n", pa_yes_no(!c->disallow_module_loading)); + pa_strbuf_printf(s, "allow-exit = %s\n", pa_yes_no(!c->disallow_exit)); pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file)); pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance)); - pa_strbuf_printf(s, "no-cpu-limit = %s\n", pa_yes_no(c->no_cpu_limit)); - pa_strbuf_printf(s, "disable-shm = %s\n", pa_yes_no(c->disable_shm)); +#ifdef HAVE_DBUS + pa_strbuf_printf(s, "local-server-type = %s\n", server_type_to_string[c->local_server_type]); +#endif + pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit)); + pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm)); pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes)); + pa_strbuf_printf(s, "lock-memory = %s\n", pa_yes_no(c->lock_memory)); + pa_strbuf_printf(s, "enable-sync-volume = %s\n", pa_yes_no(c->sync_volume)); pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time); pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time); pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path)); @@ -638,14 +746,16 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) { pa_strbuf_printf(s, "log-target = %s\n", c->auto_log_target ? "auto" : (c->log_target == PA_LOG_SYSLOG ? "syslog" : "stderr")); pa_strbuf_printf(s, "log-level = %s\n", log_level_to_string[c->log_level]); pa_strbuf_printf(s, "resample-method = %s\n", pa_resample_method_to_string(c->resample_method)); - pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_remixing)); - pa_strbuf_printf(s, "disable-lfe-remixing = %s\n", pa_yes_no(c->disable_lfe_remixing)); + pa_strbuf_printf(s, "enable-remixing = %s\n", pa_yes_no(!c->disable_remixing)); + pa_strbuf_printf(s, "enable-lfe-remixing = %s\n", pa_yes_no(!c->disable_lfe_remixing)); pa_strbuf_printf(s, "default-sample-format = %s\n", pa_sample_format_to_string(c->default_sample_spec.format)); pa_strbuf_printf(s, "default-sample-rate = %u\n", c->default_sample_spec.rate); pa_strbuf_printf(s, "default-sample-channels = %u\n", c->default_sample_spec.channels); pa_strbuf_printf(s, "default-channel-map = %s\n", pa_channel_map_snprint(cm, sizeof(cm), &c->default_channel_map)); pa_strbuf_printf(s, "default-fragments = %u\n", c->default_n_fragments); pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec); + pa_strbuf_printf(s, "sync-volume-safety-margin-usec = %u\n", c->sync_volume_safety_margin_usec); + pa_strbuf_printf(s, "sync-volume-extra-delay-usec = %d\n", c->sync_volume_extra_delay_usec); pa_strbuf_printf(s, "shm-size-bytes = %lu\n", (unsigned long) c->shm_size); pa_strbuf_printf(s, "log-meta = %s\n", pa_yes_no(c->log_meta)); pa_strbuf_printf(s, "log-time = %s\n", pa_yes_no(c->log_time)); diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h index 9cec189f..9fd6aba6 100644 --- a/src/daemon/daemon-conf.h +++ b/src/daemon/daemon-conf.h @@ -28,6 +28,7 @@ #include <pulsecore/log.h> #include <pulsecore/macro.h> +#include <pulsecore/core.h> #include <pulsecore/core-util.h> #ifdef HAVE_SYS_RESOURCE_H @@ -73,7 +74,10 @@ typedef struct pa_daemon_conf { disallow_exit, log_meta, log_time, - flat_volumes; + flat_volumes, + lock_memory, + sync_volume; + pa_server_type_t local_server_type; int exit_idle_time, scache_idle_time, auto_log_target, @@ -124,6 +128,8 @@ typedef struct pa_daemon_conf { #endif unsigned default_n_fragments, default_fragment_size_msec; + unsigned sync_volume_safety_margin_usec; + int sync_volume_extra_delay_usec; pa_sample_spec default_sample_spec; pa_channel_map default_channel_map; size_t shm_size; @@ -151,6 +157,7 @@ int pa_daemon_conf_env(pa_daemon_conf *c); int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string); int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string); +int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string); const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c); FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c); diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in index fcd2513a..6437f8f1 100644 --- a/src/daemon/daemon.conf.in +++ b/src/daemon/daemon.conf.in @@ -16,32 +16,37 @@ # USA. ## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for -## more information. Default values a commented out. Use either ; or # for +## more information. Default values are commented out. Use either ; or # for ## commenting. +changequote(`[', `]')dnl Set up m4 quoting ; daemonize = no ; fail = yes -; disallow-module-loading = no -; disallow-exit = no +; allow-module-loading = yes +; allow-exit = yes ; use-pid-file = yes ; system-instance = no -; disable-shm = no +ifelse(@HAVE_DBUS@, 1, [dnl +; local-server-type = user +])dnl +; enable-shm = yes ; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB +; lock-memory = no +; cpu-limit = no ; high-priority = yes ; nice-level = -11 -; realtime-scheduling = no +; realtime-scheduling = yes ; realtime-priority = 5 ; exit-idle-time = 20 -; module-idle-time = 20 ; scache-idle-time = 20 ; dl-search-path = (depends on architecture) ; load-default-script-file = yes -; default-script-file = @PA_DEFAULT_CONFIG_FILE@ +; default-script-file = @PA_DEFAULT_CONFIG_DIR@/default.pa ; log-target = auto ; log-level = notice @@ -50,13 +55,12 @@ ; log-backtrace = 0 ; resample-method = speex-float-3 -; disable-remixing = no -; disable-lfe-remixing = yes +; enable-remixing = yes +; enable-lfe-remixing = no ; flat-volumes = yes -; no-cpu-limit = no - +ifelse(@HAVE_SYS_RESOURCE_H@, 1, [dnl ; rlimit-fsize = -1 ; rlimit-data = -1 ; rlimit-stack = -1 @@ -71,7 +75,8 @@ ; rlimit-msgqueue = -1 ; rlimit-nice = 31 ; rlimit-rtprio = 9 -; rlimit-rtttime = 1000000 +; rlimit-rttime = 1000000 +])dnl ; default-sample-format = s16le ; default-sample-rate = 44100 @@ -80,3 +85,7 @@ ; default-fragments = 4 ; default-fragment-size-msec = 25 + +; enable-sync-volume = yes +; sync-volume-safety-margin-usec = 8000 +; sync-volume-extra-delay-usec = 0 diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in index ba8e3c80..55a7423f 100755 --- a/src/daemon/default.pa.in +++ b/src/daemon/default.pa.in @@ -18,14 +18,20 @@ # This startup script is used only if PulseAudio is started per-user # (i.e. not in system mode) +changequote(`[', `]')dnl Set up m4 quoting .nofail ### Load something into the sample cache +ifelse(@OS_IS_WIN32@, 1, [dnl +load-sample x11-bell %WINDIR%\Media\ding.wav +load-sample-dir-lazy %WINDIR%\Media\*.wav +], [dnl #load-sample-lazy x11-bell /usr/share/sounds/gtk-events/activate.wav #load-sample-lazy pulse-hotplug /usr/share/sounds/startup3.wav #load-sample-lazy pulse-coldplug /usr/share/sounds/startup3.wav #load-sample-lazy pulse-access /usr/share/sounds/generic.wav +])dnl .fail @@ -38,46 +44,71 @@ load-module module-card-restore ### stored in /usr/share/application load-module module-augment-properties -### Load audio drivers statically (it's probably better to not load -### these drivers manually, but instead use module-hal-detect -- -### see below -- for doing this automatically) +### Load audio drivers statically +### (it's probably better to not load these drivers manually, but instead +### use module-udev-detect -- see below -- for doing this automatically) +ifelse(@HAVE_ALSA@, 1, [dnl #load-module module-alsa-sink #load-module module-alsa-source device=hw:1,0 +])dnl +ifelse(@HAVE_OSS_OUTPUT@, 1, [dnl #load-module module-oss device="/dev/dsp" sink_name=output source_name=input #load-module module-oss-mmap device="/dev/dsp" sink_name=output source_name=input +])dnl +ifelse(@HAVE_WAVEOUT@, 1, [dnl +load-module module-waveout sink_name=output source_name=input +])dnl #load-module module-null-sink +ifelse(@HAVE_MKFIFO@, 1, [dnl #load-module module-pipe-sink +])dnl ### Automatically load driver modules depending on the hardware available +ifelse(1, @HAVE_UDEV@, [dnl +.ifexists module-udev-detect@PA_SOEXT@ +load-module module-udev-detect +.else +], @HAVE_HAL@, [dnl .ifexists module-hal-detect@PA_SOEXT@ load-module module-hal-detect .else -### Alternatively use the static hardware detection module (for systems that -### lack HAL support) +], [dnl +.ifexists module-detect@PA_SOEXT@ +])dnl +### Use the static hardware detection module (for systems that lack udev support) load-module module-detect .endif +ifelse(@HAVE_BLUEZ@, 1, [dnl ### Automatically load driver modules for Bluetooth hardware .ifexists module-bluetooth-discover@PA_SOEXT@ load-module module-bluetooth-discover .endif +])dnl +ifelse(@HAVE_AF_UNIX@, 1, [dnl ### Load several protocols -.ifexists module-esound-protocol-unix@PA_SOEXT@ -load-module module-esound-protocol-unix -.endif +#.ifexists module-esound-protocol-unix@PA_SOEXT@ +#load-module module-esound-protocol-unix +#.endif +load-module module-native-protocol-unix +])dnl +ifelse(@HAVE_DBUS@, 1, [dnl .ifexists module-dbus-protocol@PA_SOEXT@ load-module module-dbus-protocol .endif -load-module module-native-protocol-unix +])dnl ### Network access (may be configured with paprefs, so leave this commented ### here if you plan to use paprefs) #load-module module-esound-protocol-tcp #load-module module-native-protocol-tcp +ifelse(@HAVE_AVAHI@, 1, [dnl #load-module module-zeroconf-publish +])dnl -### Load the RTP reciever module (also configured via paprefs, see above) +ifelse(@OS_IS_WIN32@, 0, [dnl +### Load the RTP receiver module (also configured via paprefs, see above) #load-module module-rtp-recv ### Load the RTP sender module (also configured via paprefs, see above) @@ -103,19 +134,26 @@ load-module module-rescue-streams ### Make sure we always have a sink around, even if it is a null sink. load-module module-always-sink +### Honour intended role device property +load-module module-intended-roles + ### Automatically suspend sinks/sources that become idle for too long load-module module-suspend-on-idle ### If autoexit on idle is enabled we want to make sure we only quit ### when no local session needs us anymore. +.ifexists module-console-kit@PA_SOEXT@ load-module module-console-kit +.endif ### Enable positioned event sounds load-module module-position-event-sounds ### Cork music streams when a phone stream is active load-module module-cork-music-on-phone +])dnl +ifelse(@HAVE_X11@, 1, [dnl # X11 modules should not be started from default.pa so that one daemon # can be shared by multiple sessions. @@ -131,6 +169,7 @@ load-module module-cork-music-on-phone #load-module module-x11-publish #.fail #.endif +])dnl ### Make some devices default #set-default-sink output diff --git a/src/daemon/default.pa.win32 b/src/daemon/default.pa.win32 deleted file mode 100644 index d5a1e183..00000000 --- a/src/daemon/default.pa.win32 +++ /dev/null @@ -1,43 +0,0 @@ -#
-# This file is part of PulseAudio.
-#
-# PulseAudio is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# PulseAudio is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with PulseAudio; if not, write to the Free Software Foundation,
-# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
-
-
-# Load audio drivers statically
-
-load-module module-waveout sink_name=output source_name=input
-load-module module-null-sink
-
-# Load audio drivers automatically on access
-
-#add-autoload-sink output module-waveout sink_name=output source_name=input
-#add-autoload-source input module-waveout sink_name=output source_name=input
-
-# Load several protocols
-#load-module module-esound-protocol-tcp
-#load-module module-native-protocol-tcp
-#load-module module-simple-protocol-tcp
-#load-module module-cli-protocol-tcp
-
-# Make some devices default
-set-default-sink output
-set-default-source input
-
-.nofail
-
-# Load something to the sample cache
-load-sample x11-bell %WINDIR%\Media\ding.wav
-load-sample-dir-lazy %WINDIR%\Media\*.wav
diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c index 92470b49..68ab5bba 100644 --- a/src/daemon/dumpmodules.c +++ b/src/daemon/dumpmodules.c @@ -25,7 +25,6 @@ #endif #include <string.h> -#include <getopt.h> #include <stdio.h> #include <ltdl.h> @@ -90,7 +89,9 @@ static void show_info(const char *name, const char *path, void (*info)(const cha } } +#ifndef OS_IS_WIN32 extern const lt_dlsymlist lt_preloaded_symbols[]; +#endif static int is_preloaded(const char *name) { const lt_dlsymlist *l; diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in index 66501803..41a12a02 100755 --- a/src/daemon/esdcompat.in +++ b/src/daemon/esdcompat.in @@ -59,7 +59,7 @@ Ignored directives: -terminate terminate esd daemone after last client exits -nobeeps disable startup beeps -trust start esd even if use of /tmp/.esd can be insecure - -port PORT listen for connections at PORT (only for tcp/ip) + -port PORT listen for connections at PORT (only for tcp/ip) -bind ADDRESS binds to ADDRESS (only for tcp/ip) EOF exit 0 diff --git a/src/daemon/ltdl-bind-now.c b/src/daemon/ltdl-bind-now.c index 276b2a06..2ba73ce7 100644 --- a/src/daemon/ltdl-bind-now.c +++ b/src/daemon/ltdl-bind-now.c @@ -51,6 +51,10 @@ #undef PA_BIND_NOW #endif +#ifdef OS_IS_WIN32 +#undef PA_BIND_NOW +#endif + #ifdef PA_BIND_NOW /* diff --git a/src/daemon/main.c b/src/daemon/main.c index 3e50baad..94c87d15 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -33,15 +33,13 @@ #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_IOCTL_H -#include <sys/ioctl.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> #endif #ifdef HAVE_PWD_H @@ -60,6 +58,10 @@ #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> @@ -67,10 +69,10 @@ #include <pulse/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.h> -#include <pulsecore/memblock.h> #include <pulsecore/module.h> #include <pulsecore/cli-command.h> #include <pulsecore/log.h> @@ -78,19 +80,17 @@ #include <pulsecore/sioman.h> #include <pulsecore/cli-text.h> #include <pulsecore/pid.h> -#include <pulsecore/namereg.h> #include <pulsecore/random.h> -#include <pulsecore/rtsig.h> -#include <pulsecore/rtclock.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" @@ -98,7 +98,7 @@ #include "dumpmodules.h" #include "caps.h" #include "ltdl-bind-now.h" -#include "polkit.h" +#include "server-lookup.h" #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ @@ -106,7 +106,7 @@ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; #endif -#ifdef HAVE_OSS +#ifdef HAVE_OSS_WRAPPER /* padsp looks for this symbol in the running process and disables * itself if it finds it and it is set to 7 (which is actually a bit * mask). For details see padsp. */ @@ -256,9 +256,14 @@ static int change_user(void) { 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); + + 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 dropped root privileges.")); @@ -334,34 +339,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, 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. Weird shit!", 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); @@ -376,15 +397,15 @@ 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 suid_root, real_root; pa_bool_t valid_pid_file = FALSE; - gid_t gid = (gid_t) -1; pa_bool_t 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; @@ -393,7 +414,10 @@ int main(int argc, char *argv[]) { int autospawn_fd = -1; pa_bool_t 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. */ + pa_bool_t start_server; #endif pa_log_set_ident("pulseaudio"); @@ -404,47 +428,39 @@ int main(int argc, char *argv[]) { /* Disable lazy relocations to make usage of external libraries more deterministic for our RT threads. We abuse __OPTIMIZE__ as - a check whether we are a debug build or not. + a check whether we are a debug build or not. This all is + admittedly a bit snake-oilish. */ 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"))) - pa_assert_se(execv(rp, argv) == 0); - else - pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); - } -#endif + if ((canonical_rp = pa_realpath(PA_BINARY))) { -#ifdef HAVE_GETUID - real_root = getuid() == 0; - suid_root = !real_root && geteuid() == 0; -#else - real_root = FALSE; - suid_root = FALSE; -#endif + 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); - if (!real_root) { - /* Drop all capabilities except CAP_SYS_NICE */ - pa_limit_caps(); + pa_xfree(rp); - /* Drop privileges, but keep CAP_SYS_NICE */ - pa_drop_root(); + } else + pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?"); - /* After dropping root, the effective set is reset, hence, - * let's raise it again */ - pa_limit_caps(); + pa_xfree(canonical_rp); - /* When capabilities are not supported we will not be able to - * acquire RT sched anymore. But yes, that's the way it is. It - * is just too risky tun let PA run as root all the time. */ + } else + pa_log_warn("Couldn't canonicalize binary path, cannot self execute."); } +#endif if ((e = getenv("PULSE_PASSED_FD"))) { passed_fd = atoi(e); @@ -453,14 +469,16 @@ int main(int argc, char *argv[]) { passed_fd = -1; } - pa_close_all(passed_fd, -1); + /* We might be autospawned, in which case have no idea in which + * context we have been started. Let's cleanup our execution + * context as good as possible */ + pa_reset_personality(); + pa_drop_root(); + pa_close_all(passed_fd, -1); pa_reset_sigs(-1); pa_unblock_sigs(-1); - - /* At this point, we are a normal user, possibly with CAP_NICE if - * we were started SUID. If we are started as normal root, than we - * still are normal root. */ + pa_reset_priority(); setlocale(LC_ALL, ""); pa_init_i18n(); @@ -486,150 +504,32 @@ int main(int argc, char *argv[]) { pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET); pa_log_set_show_backtrace(conf->log_backtrace); - pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root)); - - if (!real_root && pa_have_caps()) { -#ifdef HAVE_SYS_RESOURCE_H - struct rlimit rl; -#endif - pa_bool_t allow_high_priority = FALSE, allow_realtime = FALSE; - - /* Let's better not enable high prio or RT by default */ - - if (conf->high_priority && !allow_high_priority) { - if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) { - pa_log_info(_("We're in the group '%s', allowing high-priority scheduling."), PA_REALTIME_GROUP); - allow_high_priority = TRUE; - } - } - - if (conf->realtime_scheduling && !allow_realtime) { - if (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) > 0) { - pa_log_info(_("We're in the group '%s', allowing real-time scheduling."), PA_REALTIME_GROUP); - allow_realtime = TRUE; - } - } - -#ifdef HAVE_POLKIT - if (conf->high_priority && !allow_high_priority) { - if (pa_polkit_check("org.pulseaudio.acquire-high-priority") > 0) { - pa_log_info(_("PolicyKit grants us acquire-high-priority privilege.")); - allow_high_priority = TRUE; - } else - pa_log_info(_("PolicyKit refuses acquire-high-priority privilege.")); - } - - if (conf->realtime_scheduling && !allow_realtime) { - if (pa_polkit_check("org.pulseaudio.acquire-real-time") > 0) { - pa_log_info(_("PolicyKit grants us acquire-real-time privilege.")); - allow_realtime = TRUE; - } else - pa_log_info(_("PolicyKit refuses acquire-real-time privilege.")); - } -#endif - - if (!allow_high_priority && !allow_realtime) { - - /* OK, there's no further need to keep CAP_NICE. Hence - * let's give it up early */ - - pa_drop_caps(); - } - -#ifdef RLIMIT_RTPRIO - if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0) - if (rl.rlim_cur > 0) { - pa_log_info("RLIMIT_RTPRIO is set to %u, allowing real-time scheduling.", (unsigned) rl.rlim_cur); - allow_realtime = TRUE; - } -#endif -#ifdef RLIMIT_NICE - if (getrlimit(RLIMIT_NICE, &rl) >= 0) - if (rl.rlim_cur > 20 ) { - pa_log_info("RLIMIT_NICE is set to %u, allowing high-priority scheduling.", (unsigned) rl.rlim_cur); - allow_high_priority = TRUE; - } -#endif - - if ((conf->high_priority && !allow_high_priority) || - (conf->realtime_scheduling && !allow_realtime)) - pa_log_info(_("Called SUID root and real-time and/or high-priority scheduling was requested in the configuration. However, we lack the necessary privileges:\n" - "We are not in group '%s', PolicyKit refuse to grant us the requested privileges and we have no increase RLIMIT_NICE/RLIMIT_RTPRIO resource limits.\n" - "For enabling real-time/high-priority scheduling please acquire the appropriate PolicyKit privileges, or become a member of '%s', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user."), - PA_REALTIME_GROUP, PA_REALTIME_GROUP); - - - if (!allow_realtime) - conf->realtime_scheduling = FALSE; - - if (!allow_high_priority) - conf->high_priority = FALSE; +#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(); } -#ifdef HAVE_SYS_RESOURCE_H - /* Reset resource limits. If we are run as root (for system mode) - * this might end up increasing the limits, which is intended - * behaviour. For all other cases, i.e. started as normal user, or - * SUID root at this point we should have no CAP_SYS_RESOURCE and - * increasing the limits thus should fail. Which is, too, intended - * behaviour */ + start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (getuid() == 0 && conf->local_server_type == PA_SERVER_TYPE_SYSTEM); - set_all_rlimits(conf); -#endif - - if (conf->high_priority && !pa_can_high_priority()) { - pa_log_info(_("High-priority scheduling enabled in configuration but not allowed by policy.")); - conf->high_priority = FALSE; + 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; } - - if (conf->high_priority && (conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START)) - pa_raise_priority(conf->nice_level); - - pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority())); - - if (!real_root && pa_have_caps()) { - pa_bool_t drop; - - drop = (conf->cmd != PA_CMD_DAEMON && conf->cmd != PA_CMD_START) || !conf->realtime_scheduling; - -#ifdef RLIMIT_RTPRIO - if (!drop) { - struct rlimit rl; - /* At this point we still have CAP_NICE if we were loaded - * SUID root. If possible let's acquire RLIMIT_RTPRIO - * instead and give CAP_NICE up. */ - - if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0) { - - if (rl.rlim_cur >= 9) - drop = TRUE; - else { - rl.rlim_max = rl.rlim_cur = 9; - - if (setrlimit(RLIMIT_RTPRIO, &rl) >= 0) { - pa_log_info(_("Successfully increased RLIMIT_RTPRIO")); - drop = TRUE; - } else - pa_log_warn(_("RLIMIT_RTPRIO failed: %s"), pa_cstrerror(errno)); - } - } - } #endif - if (drop) { - pa_log_info(_("Giving up CAP_NICE")); - pa_drop_caps(); - suid_root = FALSE; - } - } - - if (conf->realtime_scheduling && !pa_can_realtime()) { - pa_log_info(_("Real-time scheduling enabled in configuration but not allowed by policy.")); - conf->realtime_scheduling = FALSE; - } - - pa_log_debug("Can realtime: %s, can high-priority: %s", pa_yes_no(pa_can_realtime()), pa_yes_no(pa_can_high_priority())); - LTDL_SET_PRELOADED_SYMBOLS(); pa_ltdl_init(); ltdl_init = TRUE; @@ -653,6 +553,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); @@ -663,6 +569,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)); @@ -677,6 +588,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; @@ -684,6 +601,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 { @@ -696,6 +618,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 @@ -705,6 +632,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; @@ -714,18 +646,73 @@ int main(int argc, char *argv[]) { pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START); } - if (real_root && !conf->system_instance) + 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).")); - else if (!real_root && conf->system_instance) { +#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; + pa_bool_t 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!")); @@ -761,8 +748,9 @@ int main(int argc, char *argv[]) { } if (conf->daemonize) { +#ifdef HAVE_FORK pid_t child; - int tty_fd; +#endif if (pa_stdio_acquire() < 0) { pa_log(_("Failed to acquire stdio.")); @@ -771,12 +759,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; } @@ -822,22 +811,60 @@ int main(int argc, char *argv[]) { pa_log_set_target(PA_LOG_SYSLOG); #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 @@ -850,23 +877,25 @@ 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); +#ifdef HAVE_SYS_RESOURCE_H + set_all_rlimits(conf); +#endif + pa_rtclock_hrtimer_enable(); + + 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); @@ -888,6 +917,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 @@ -910,8 +941,8 @@ int main(int argc, char *argv[]) { pa_xfree(s); if ((s = pa_session_id())) { - pa_log_info(_("Session ID is %s."), s); - pa_xfree(s); + pa_log_info(_("Session ID is %s."), s); + pa_xfree(s); } if (!(s = pa_get_runtime_dir())) @@ -924,8 +955,15 @@ 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()) + pa_log_warn(_("OK, so you are running PA in system mode. Please note that you most likely shouldn't be doing that.\n" + "If you do it nonetheless then it's your own fault if things don't work as expected.\n" + "Please read http://pulseaudio.org/wiki/WhatIsWrongWithSystemMode for an explanation why system mode is usually a bad idea.")); + if (conf->use_pid_file) { int z; @@ -953,12 +991,16 @@ int main(int argc, char *argv[]) { else pa_log_info(_("Dude, your kernel stinks! The chef's recommendation today is Linux with high-resolution timers enabled!")); - pa_rtclock_hrtimer_enable(); - -#ifdef SIGRTMIN - /* Valgrind uses SIGRTMAX. To easy debugging we don't use it here */ - pa_rtsig_configure(SIGRTMIN, SIGRTMAX-1); + if (conf->lock_memory) { +#ifdef HAVE_SYS_MMAN_H + if (mlockall(MCL_FUTURE) < 0) + pa_log_warn("mlockall() failed: %s", pa_cstrerror(errno)); + else + pa_log_info("Successfully locked process into memory."); +#else + pa_log_warn("Memory locking requested but not supported on platform."); #endif + } pa_memtrap_install(); @@ -973,6 +1015,8 @@ int main(int argc, char *argv[]) { 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->sync_volume_safety_margin_usec = conf->sync_volume_safety_margin_usec; + c->sync_volume_extra_delay_usec = conf->sync_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; @@ -980,9 +1024,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->sync_volume = !!conf->sync_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); @@ -1001,54 +1058,73 @@ int main(int argc, char *argv[]) { 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 + 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))) + goto finish; + 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.")); + if (start_server && !(server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server"))) goto finish; - } +#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; @@ -1059,8 +1135,12 @@ 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) { @@ -1071,7 +1151,7 @@ finish: } #ifdef OS_IS_WIN32 - if (win32_timer) + if (mainloop && win32_timer) pa_mainloop_get_api(mainloop)->time_free(win32_timer); #endif @@ -1086,9 +1166,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 @@ -1101,6 +1186,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 diff --git a/src/daemon/org.pulseaudio.policy.in b/src/daemon/org.pulseaudio.policy.in deleted file mode 100644 index 1d0b6a7d..00000000 --- a/src/daemon/org.pulseaudio.policy.in +++ /dev/null @@ -1,50 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?><!--*-nxml-*--> -<!DOCTYPE policyconfig PUBLIC - "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" - "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd"> - -<!-- -This file is part of PulseAudio. - -PulseAudio is free software; you can redistribute it and/or modify it -under the terms of the GNU Lesser General Public License as -published by the Free Software Foundation; either version 2.1 of the -License, or (at your option) any later version. - -PulseAudio is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General -Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with PulseAudio; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA. ---> - -<policyconfig> - <vendor>The PulseAudio Project</vendor> - <vendor_url>http://pulseaudio.org/</vendor_url> - <icon_name>audio-card</icon_name> - - <action id="org.pulseaudio.acquire-real-time"> - <_description>Real-time scheduling for the PulseAudio daemon</_description> - <_message>System policy prevents PulseAudio from acquiring real-time scheduling.</_message> - <defaults> - <allow_any>no</allow_any> - <allow_inactive>no</allow_inactive> - <allow_active>no</allow_active> - </defaults> - </action> - - <action id="org.pulseaudio.acquire-high-priority"> - <_description>High-priority scheduling (negative Unix nice level) for the PulseAudio daemon</_description> - <_message>System policy prevents PulseAudio from acquiring high-priority scheduling.</_message> - <defaults> - <allow_any>no</allow_any> - <allow_inactive>no</allow_inactive> - <allow_active>no</allow_active> - </defaults> - </action> - -</policyconfig> diff --git a/src/daemon/polkit.c b/src/daemon/polkit.c deleted file mode 100644 index 9799e094..00000000 --- a/src/daemon/polkit.c +++ /dev/null @@ -1,172 +0,0 @@ -/*** - This file is part of PulseAudio. - - Copyright 2004-2006 Lennart Poettering - Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB - - PulseAudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2.1 of the License, - or (at your option) any later version. - - PulseAudio is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with PulseAudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <unistd.h> -#include <stdlib.h> -#include <inttypes.h> - -#include <dbus/dbus.h> -#include <polkit-dbus/polkit-dbus.h> - -#include <pulse/i18n.h> - -#include <pulsecore/log.h> -#include <pulsecore/macro.h> - -#include "polkit.h" - -int pa_polkit_check(const char *action_id) { - int ret = -1; - DBusError dbus_error; - DBusConnection *bus = NULL; - PolKitCaller *caller = NULL; - PolKitAction *action = NULL; - PolKitContext *context = NULL; - PolKitError *polkit_error = NULL; - PolKitSession *session = NULL; - PolKitResult polkit_result; - - dbus_error_init(&dbus_error); - - if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error))) { - pa_log_error(_("Cannot connect to system bus: %s"), dbus_error.message); - goto finish; - } - - /* There seems to be a bug in some versions of D-Bus that causes - * dbus_shutdown() to call exit() when a connection without this - * flag disabled was created during runtime.*/ - dbus_connection_set_exit_on_disconnect(bus, FALSE); - - if (!(caller = polkit_caller_new_from_pid(bus, getpid(), &dbus_error))) { - pa_log_error(_("Cannot get caller from PID: %s"), dbus_error.message); - goto finish; - } - - /* This function is called when PulseAudio is called SUID root. We - * want to authenticate the real user that called us and not the - * effective user we gained through being SUID root. Hence we - * overwrite the UID caller data here explicitly, just for - * paranoia. In fact PolicyKit should fill in the UID here anyway - * -- an not the EUID or any other user id. */ - - if (!(polkit_caller_set_uid(caller, getuid()))) { - pa_log_error(_("Cannot set UID on caller object.")); - goto finish; - } - - if (!(polkit_caller_get_ck_session(caller, &session))) { - pa_log_error(_("Failed to get CK session.")); - goto finish; - } - - /* We need to overwrite the UID in both the caller and the session - * object */ - - if (!(polkit_session_set_uid(session, getuid()))) { - pa_log_error(_("Cannot set UID on session object.")); - goto finish; - } - - if (!(action = polkit_action_new())) { - pa_log_error(_("Cannot allocate PolKitAction.")); - goto finish; - } - - if (!polkit_action_set_action_id(action, action_id)) { - pa_log_error(_("Cannot set action_id")); - goto finish; - } - - if (!(context = polkit_context_new())) { - pa_log_error(_("Cannot allocate PolKitContext.")); - goto finish; - } - - if (!polkit_context_init(context, &polkit_error)) { - pa_log_error(_("Cannot initialize PolKitContext: %s"), polkit_error_get_error_message(polkit_error)); - goto finish; - } - - for (;;) { - - polkit_result = polkit_context_is_caller_authorized(context, action, caller, TRUE, &polkit_error); - - if (polkit_error_is_set(polkit_error)) { - pa_log_error(_("Could not determine whether caller is authorized: %s"), polkit_error_get_error_message(polkit_error)); - goto finish; - } - - if (polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS || - polkit_result == POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS || - polkit_result == POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT - ) { - - if (polkit_auth_obtain(action_id, 0, getpid(), &dbus_error)) { - polkit_result = POLKIT_RESULT_YES; - break; - } - - if (dbus_error_is_set(&dbus_error)) { - pa_log_error(_("Cannot obtain auth: %s"), dbus_error.message); - goto finish; - } - } - - break; - } - - if (polkit_result != POLKIT_RESULT_YES && polkit_result != POLKIT_RESULT_NO) - pa_log_warn(_("PolicyKit responded with '%s'"), polkit_result_to_string_representation(polkit_result)); - - ret = polkit_result == POLKIT_RESULT_YES; - -finish: - - if (caller) - polkit_caller_unref(caller); - - if (action) - polkit_action_unref(action); - - if (context) - polkit_context_unref(context); - - if (bus) - dbus_connection_unref(bus); - - dbus_error_free(&dbus_error); - - if (polkit_error) - polkit_error_free(polkit_error); - - return ret; -} diff --git a/src/daemon/pulseaudio-kde.desktop.in b/src/daemon/pulseaudio-kde.desktop.in new file mode 100644 index 00000000..06846421 --- /dev/null +++ b/src/daemon/pulseaudio-kde.desktop.in @@ -0,0 +1,11 @@ +[Desktop Entry] +Version=1.0 +Encoding=UTF-8 +_Name=PulseAudio Sound System KDE Routing Policy +_Comment=Start the PulseAudio Sound System with KDE Routing Policy +Exec=start-pulseaudio-kde +Terminal=false +Type=Application +Categories= +GenericName= +OnlyShowIn=KDE; diff --git a/src/daemon/pulseaudio-system.conf b/src/daemon/pulseaudio-system.conf new file mode 100644 index 00000000..edddaf93 --- /dev/null +++ b/src/daemon/pulseaudio-system.conf @@ -0,0 +1,37 @@ +<?xml version="1.0"?><!--*-nxml-*--> +<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd"> + +<!-- +This file is part of PulseAudio. + +PulseAudio is free software; you can redistribute it and/or modify it +under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation; either version 2.1 of the +License, or (at your option) any later version. + +PulseAudio is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General +Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with PulseAudio; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA. +--> + +<busconfig> + + <!-- System-wide PulseAudio runs as 'pulse' user. This fragment is + not necessary for user PulseAudio instances. --> + + <policy user="pulse"> + <allow own="org.pulseaudio.Server"/> + + <!-- Allow pulseaudio to talk to HAL for device detection --> + <allow send_destination="org.freedesktop.Hal" send_interface="org.freedesktop.Hal.Manager"/> + <allow send_destination="org.freedesktop.Hal" send_interface="org.freedesktop.Hal.Device"/> + </policy> + +</busconfig> diff --git a/src/daemon/server-lookup.c b/src/daemon/server-lookup.c new file mode 100644 index 00000000..45796e72 --- /dev/null +++ b/src/daemon/server-lookup.c @@ -0,0 +1,522 @@ +/*** + This file is part of PulseAudio. + + Copyright 2009 Tanu Kaskinen + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published + by the Free Software Foundation; either version 2.1 of the License, + or (at your option) any later version. + + PulseAudio is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with PulseAudio; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <dbus/dbus.h> + +#include <pulse/client-conf.h> +#include <pulse/xmalloc.h> + +#include <pulsecore/core.h> +#include <pulsecore/core-util.h> +#include <pulsecore/dbus-shared.h> +#include <pulsecore/macro.h> +#include <pulsecore/protocol-dbus.h> + +#include "server-lookup.h" + +#define OBJECT_PATH "/org/pulseaudio/server_lookup1" +#define INTERFACE "org.PulseAudio.ServerLookup1" + +struct pa_dbusobj_server_lookup { + pa_core *core; + pa_dbus_connection *conn; + pa_bool_t path_registered; +}; + +static const char introspection[] = + DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE + "<node>" + " <!-- If you are looking for documentation make sure to check out\n" + " http://pulseaudio.org/wiki/DBusInterface -->\n" + " <interface name=\"" INTERFACE "\">\n" + " <property name=\"Address\" type=\"s\" access=\"read\"/>\n" + " </interface>\n" + " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n" + " <method name=\"Introspect\">\n" + " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n" + " </method>\n" + " </interface>\n" + " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n" + " <method name=\"Get\">\n" + " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"value\" type=\"v\" direction=\"out\"/>\n" + " </method>\n" + " <method name=\"Set\">\n" + " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"value\" type=\"v\" direction=\"in\"/>\n" + " </method>\n" + " <method name=\"GetAll\">\n" + " <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n" + " <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n" + " </method>\n" + " </interface>\n" + "</node>\n"; + +static void unregister_cb(DBusConnection *conn, void *user_data) { + pa_dbusobj_server_lookup *sl = user_data; + + pa_assert(sl); + pa_assert(sl->path_registered); + + sl->path_registered = FALSE; +} + +static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { + DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED; + const char *i = introspection; + DBusMessage *reply = NULL; + + pa_assert(conn); + pa_assert(msg); + + if (!(reply = dbus_message_new_method_return(msg))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID)) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + +finish: + if (reply) + dbus_message_unref(reply); + + return r; +} + +enum get_address_result_t { + SUCCESS, + FAILED_TO_LOAD_CLIENT_CONF, + SERVER_FROM_TYPE_FAILED +}; + +/* Caller frees the returned address. */ +static enum get_address_result_t get_address(pa_server_type_t server_type, char **address) { + enum get_address_result_t r = SUCCESS; + pa_client_conf *conf = pa_client_conf_new(); + + *address = NULL; + + if (pa_client_conf_load(conf, NULL) < 0) { + r = FAILED_TO_LOAD_CLIENT_CONF; + goto finish; + } + + if (conf->default_dbus_server) + *address = pa_xstrdup(conf->default_dbus_server); + else if (!(*address = pa_get_dbus_address_from_server_type(server_type))) { + r = SERVER_FROM_TYPE_FAILED; + goto finish; + } + +finish: + pa_client_conf_free(conf); + return r; +} + +static DBusHandlerResult handle_get_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { + DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED; + DBusMessage *reply = NULL; + char *address = NULL; + DBusMessageIter msg_iter; + DBusMessageIter variant_iter; + + pa_assert(conn); + pa_assert(msg); + pa_assert(sl); + + switch (get_address(sl->core->server_type, &address)) { + case SUCCESS: + if (!(reply = dbus_message_new_method_return(msg))) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + dbus_message_iter_init_append(reply, &msg_iter); + if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_close_container(&msg_iter, &variant_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + case FAILED_TO_LOAD_CLIENT_CONF: + if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + case SERVER_FROM_TYPE_FAILED: + if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + default: + pa_assert_not_reached(); + } + +finish: + pa_xfree(address); + if (reply) + dbus_message_unref(reply); + + return r; +} + +static DBusHandlerResult handle_get(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { + DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED; + const char* interface; + const char* property; + DBusMessage *reply = NULL; + + pa_assert(conn); + pa_assert(msg); + pa_assert(sl); + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) { + if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + } + + if (*interface && !pa_streq(interface, INTERFACE)) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + + if (!pa_streq(property, "Address")) { + if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + } + + r = handle_get_address(conn, msg, sl); + +finish: + if (reply) + dbus_message_unref(reply); + + return r; +} + +static DBusHandlerResult handle_set(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { + DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED; + const char* interface; + const char* property; + DBusMessage *reply = NULL; + + pa_assert(conn); + pa_assert(msg); + pa_assert(sl); + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) { + if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + } + + if (*interface && !pa_streq(interface, INTERFACE)) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + + if (!pa_streq(property, "Address")) { + if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + } + + if (!(reply = dbus_message_new_error_printf(msg, DBUS_ERROR_ACCESS_DENIED, "%s: Property not settable", property))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + +finish: + if (reply) + dbus_message_unref(reply); + + return r; +} + +static DBusHandlerResult handle_get_all(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) { + DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED; + DBusMessage *reply = NULL; + const char *property = "Address"; + char *interface = NULL; + char *address = NULL; + DBusMessageIter msg_iter; + DBusMessageIter dict_iter; + DBusMessageIter dict_entry_iter; + DBusMessageIter variant_iter; + + pa_assert(conn); + pa_assert(msg); + pa_assert(sl); + + if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID)) { + if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + } + + switch (get_address(sl->core->server_type, &address)) { + case SUCCESS: + if (!(reply = dbus_message_new_method_return(msg))) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + dbus_message_iter_init_append(reply, &msg_iter); + if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &property)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_close_container(&dict_entry_iter, &variant_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_close_container(&dict_iter, &dict_entry_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_message_iter_close_container(&msg_iter, &dict_iter)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + case FAILED_TO_LOAD_CLIENT_CONF: + if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + case SERVER_FROM_TYPE_FAILED: + if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) { + r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + goto finish; + } + if (!dbus_connection_send(conn, reply, NULL)) { + r = DBUS_HANDLER_RESULT_NEED_MEMORY; + goto finish; + } + r = DBUS_HANDLER_RESULT_HANDLED; + goto finish; + + default: + pa_assert_not_reached(); + } + +finish: + pa_xfree(address); + if (reply) + dbus_message_unref(reply); + + return r; +} + +static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void *user_data) { + pa_dbusobj_server_lookup *sl = user_data; + + pa_assert(conn); + pa_assert(msg); + pa_assert(sl); + + /* pa_log("Got message! type = %s path = %s iface = %s member = %s dest = %s", dbus_message_type_to_string(dbus_message_get_type(msg)), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_destination(msg)); */ + + if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") || + (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Introspect"))) + return handle_introspect(conn, msg, sl); + + if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Get") || + (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Get"))) + return handle_get(conn, msg, sl); + + if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Set") || + (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Set"))) + return handle_set(conn, msg, sl); + + if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "GetAll") || + (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "GetAll"))) + return handle_get_all(conn, msg, sl); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable vtable = { + .unregister_function = unregister_cb, + .message_function = message_cb, + .dbus_internal_pad1 = NULL, + .dbus_internal_pad2 = NULL, + .dbus_internal_pad3 = NULL, + .dbus_internal_pad4 = NULL +}; + +pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c) { + pa_dbusobj_server_lookup *sl; + DBusError error; + + dbus_error_init(&error); + + sl = pa_xnew(pa_dbusobj_server_lookup, 1); + sl->core = c; + sl->path_registered = FALSE; + + if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) { + pa_log("Unable to contact D-Bus: %s: %s", error.name, error.message); + goto fail; + } + + if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH, &vtable, sl)) { + pa_log("dbus_connection_register_object_path() failed for " OBJECT_PATH "."); + goto fail; + } + + sl->path_registered = TRUE; + + return sl; + +fail: + dbus_error_free(&error); + + pa_dbusobj_server_lookup_free(sl); + + return NULL; +} + +void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl) { + pa_assert(sl); + + if (sl->path_registered) { + pa_assert(sl->conn); + if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH)) + pa_log_debug("dbus_connection_unregister_object_path() failed for " OBJECT_PATH "."); + } + + if (sl->conn) + pa_dbus_connection_unref(sl->conn); + + pa_xfree(sl); +} diff --git a/src/daemon/polkit.h b/src/daemon/server-lookup.h index 018f6ef1..c930d5b7 100644 --- a/src/daemon/polkit.h +++ b/src/daemon/server-lookup.h @@ -1,10 +1,10 @@ -#ifndef foopolkithfoo -#define foopolkithfoo +#ifndef fooserverlookuphfoo +#define fooserverlookuphfoo /*** This file is part of PulseAudio. - Copyright 2007 Lennart Poettering + Copyright 2009 Tanu Kaskinen PulseAudio is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published @@ -22,6 +22,19 @@ USA. ***/ -int pa_polkit_check(const char *action); +/* This object implements the D-Bus object at path + * /org/pulseaudio/server_lookup. Implemented interfaces + * are org.pulseaudio.ServerLookup and org.freedesktop.DBus.Introspectable. + * + * See http://pulseaudio.org/wiki/DBusInterface for the ServerLookup interface + * documentation. + */ + +#include <pulsecore/core.h> + +typedef struct pa_dbusobj_server_lookup pa_dbusobj_server_lookup; + +pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c); +void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl); #endif diff --git a/src/daemon/start-pulseaudio-kde.in b/src/daemon/start-pulseaudio-kde.in new file mode 100755 index 00000000..c319e7dd --- /dev/null +++ b/src/daemon/start-pulseaudio-kde.in @@ -0,0 +1,30 @@ +#!/bin/sh + +# This file is part of PulseAudio. +# +# PulseAudio is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PulseAudio is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with PulseAudio; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. + +set -e + +[ -z "$PULSE_SERVER" ] + +@PA_BINARY@ --start "$@" + +if [ x"$DISPLAY" != x ] ; then + + @PACTL_BINARY@ load-module module-device-manager "do_routing=1" > /dev/null + +fi diff --git a/src/daemon/start-pulseaudio-x11.in b/src/daemon/start-pulseaudio-x11.in index c57c489d..391a6d3c 100755 --- a/src/daemon/start-pulseaudio-x11.in +++ b/src/daemon/start-pulseaudio-x11.in @@ -19,8 +19,6 @@ set -e -[ -z "$PULSE_SERVER" ] - @PA_BINARY@ --start "$@" if [ x"$DISPLAY" != x ] ; then diff --git a/src/daemon/system.pa.in b/src/daemon/system.pa.in index 5541bbe4..aaefd1d1 100755 --- a/src/daemon/system.pa.in +++ b/src/daemon/system.pa.in @@ -20,11 +20,11 @@ # mode. ### Automatically load driver modules depending on the hardware available -.ifexists module-hal-detect@PA_SOEXT@ -load-module module-hal-detect +.ifexists module-udev-detect@PA_SOEXT@ +load-module module-udev-detect .else ### Alternatively use the static hardware detection module (for systems that -### lack HAL support) +### lack udev support) load-module module-detect .endif @@ -33,7 +33,8 @@ load-module module-detect load-module module-esound-protocol-unix .endif .ifexists module-dbus-protocol@PA_SOEXT@ -load-module module-dbus-protocol +### If you want to allow TCP connections, set access to "remote" or "local,remote". +load-module module-dbus-protocol access=local .endif load-module module-native-protocol-unix |
