summaryrefslogtreecommitdiffstats
path: root/src/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon')
-rw-r--r--src/daemon/caps.c85
-rw-r--r--src/daemon/caps.h9
-rw-r--r--src/daemon/cmdline.c58
-rw-r--r--src/daemon/cmdline.h2
-rw-r--r--src/daemon/cpulimit.c19
-rw-r--r--src/daemon/cpulimit.h2
-rw-r--r--src/daemon/daemon-conf.c329
-rw-r--r--src/daemon/daemon-conf.h49
-rw-r--r--src/daemon/daemon.conf.in99
-rwxr-xr-xsrc/daemon/default.pa.in34
-rw-r--r--src/daemon/dumpmodules.c9
-rw-r--r--src/daemon/dumpmodules.h2
-rwxr-xr-xsrc/daemon/esdcompat.in2
-rw-r--r--src/daemon/ltdl-bind-now.c47
-rw-r--r--src/daemon/ltdl-bind-now.h2
-rw-r--r--src/daemon/main.c482
-rw-r--r--src/daemon/org.pulseaudio.policy50
-rw-r--r--src/daemon/polkit.c165
-rw-r--r--src/daemon/polkit.h27
19 files changed, 1070 insertions, 402 deletions
diff --git a/src/daemon/caps.c b/src/daemon/caps.c
index 5b4008a5..ae07119c 100644
--- a/src/daemon/caps.c
+++ b/src/daemon/caps.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -63,13 +61,16 @@ void pa_drop_root(void) {
pa_log_info("Dropping root priviliges.");
#if defined(HAVE_SETRESUID)
- setresuid(uid, uid, uid);
+ pa_assert_se(setresuid(uid, uid, uid) >= 0);
#elif defined(HAVE_SETREUID)
- setreuid(uid, uid);
+ pa_assert_se(setreuid(uid, uid) >= 0);
#else
- setuid(uid);
- seteuid(uid);
+ pa_assert_se(setuid(uid) >= 0);
+ pa_assert_se(seteuid(uid) >= 0);
#endif
+
+ pa_assert_se(getuid() == uid);
+ pa_assert_se(geteuid() == uid);
}
#else
@@ -82,69 +83,65 @@ void pa_drop_root(void) {
#if defined(HAVE_SYS_CAPABILITY_H) && defined(HAVE_SYS_PRCTL_H)
/* Limit permitted capabilities set to CAPSYS_NICE */
-int pa_limit_caps(void) {
- int r = -1;
+void pa_limit_caps(void) {
cap_t caps;
cap_value_t nice_cap = CAP_SYS_NICE;
- caps = cap_init();
- pa_assert(caps);
- cap_clear(caps);
- cap_set_flag(caps, CAP_EFFECTIVE, 1, &nice_cap, CAP_SET);
- cap_set_flag(caps, CAP_PERMITTED, 1, &nice_cap, CAP_SET);
+ 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)
- goto fail;
-
- if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) < 0)
- goto fail;
+ /* 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_log_info("Dropped capabilities successfully.");
+ pa_assert_se(cap_free(caps) == 0);
- r = 1;
-
-fail:
- cap_free(caps);
-
- return r;
+ pa_assert_se(prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == 0);
}
/* Drop all capabilities, effectively becoming a normal user */
-int pa_drop_caps(void) {
+void pa_drop_caps(void) {
cap_t caps;
- int r = -1;
-
- caps = cap_init();
- pa_assert(caps);
- cap_clear(caps);
+ pa_assert_se(prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == 0);
- prctl(PR_SET_KEEPCAPS, 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);
- if (cap_set_proc(caps) < 0) {
- pa_log("Failed to drop capabilities: %s", pa_cstrerror(errno));
- goto fail;
- }
+ pa_assert_se(!pa_have_caps());
+}
- r = 0;
+pa_bool_t pa_have_caps(void) {
+ cap_t caps;
+ cap_flag_value_t flag = CAP_CLEAR;
-fail:
- cap_free(caps);
+ pa_assert_se(caps = cap_get_proc());
+ pa_assert_se(cap_get_flag(caps, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0);
+ pa_assert_se(cap_free(caps) == 0);
- return r;
+ return flag == CAP_SET;
}
#else
/* NOOPs in case capabilities are not available. */
-int pa_limit_caps(void) {
- return 0;
+void pa_limit_caps(void) {
}
-int pa_drop_caps(void) {
+void pa_drop_caps(void) {
pa_drop_root();
- return 0;
}
-#endif
+pa_bool_t pa_have_caps(void) {
+ return FALSE;
+}
+#endif
diff --git a/src/daemon/caps.h b/src/daemon/caps.h
index 4cd09578..176aa90e 100644
--- a/src/daemon/caps.h
+++ b/src/daemon/caps.h
@@ -1,8 +1,6 @@
#ifndef foocapshfoo
#define foocapshfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -24,8 +22,11 @@
USA.
***/
+#include <pulsecore/macro.h>
+
void pa_drop_root(void);
-int pa_limit_caps(void);
-int pa_drop_caps(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 d14002f6..4b2466ce 100644
--- a/src/daemon/cmdline.c
+++ b/src/daemon/cmdline.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -49,6 +47,7 @@ enum {
ARG_FAIL,
ARG_LOG_LEVEL,
ARG_HIGH_PRIORITY,
+ ARG_REALTIME,
ARG_DISALLOW_MODULE_LOADING,
ARG_EXIT_IDLE_TIME,
ARG_MODULE_IDLE_TIME,
@@ -65,11 +64,12 @@ enum {
ARG_DISABLE_SHM,
ARG_DUMP_RESAMPLE_METHODS,
ARG_SYSTEM,
- ARG_CLEANUP_SHM
+ ARG_CLEANUP_SHM,
+ ARG_START
};
/* Tabel for getopt_long() */
-static struct option long_options[] = {
+static const struct option long_options[] = {
{"help", 0, 0, ARG_HELP},
{"version", 0, 0, ARG_VERSION},
{"dump-conf", 0, 0, ARG_DUMP_CONF},
@@ -79,6 +79,7 @@ static struct option long_options[] = {
{"verbose", 2, 0, ARG_LOG_LEVEL},
{"log-level", 2, 0, ARG_LOG_LEVEL},
{"high-priority", 2, 0, ARG_HIGH_PRIORITY},
+ {"realtime", 2, 0, ARG_REALTIME},
{"disallow-module-loading", 2, 0, ARG_DISALLOW_MODULE_LOADING},
{"exit-idle-time", 2, 0, ARG_EXIT_IDLE_TIME},
{"module-idle-time", 2, 0, ARG_MODULE_IDLE_TIME},
@@ -89,6 +90,7 @@ static struct option long_options[] = {
{"dl-search-path", 1, 0, ARG_DL_SEARCH_PATH},
{"resample-method", 1, 0, ARG_RESAMPLE_METHOD},
{"kill", 0, 0, ARG_KILL},
+ {"start", 0, 0, ARG_START},
{"use-pid-file", 2, 0, ARG_USE_PID_FILE},
{"check", 0, 0, ARG_CHECK},
{"system", 2, 0, ARG_SYSTEM},
@@ -103,7 +105,7 @@ void pa_cmdline_help(const char *argv0) {
const char *e;
pa_assert(argv0);
-
+
if ((e = strrchr(argv0, '/')))
e++;
else
@@ -117,6 +119,7 @@ void pa_cmdline_help(const char *argv0) {
" --dump-modules Dump list of available modules\n"
" --dump-resample-methods Dump available resample methods\n"
" --cleanup-shm Cleanup stale shared memory segments\n"
+ " --start Start the daemon if it is not running\n"
" -k --kill Kill a running daemon\n"
" --check Check for a running daemon\n\n"
@@ -124,8 +127,12 @@ void pa_cmdline_help(const char *argv0) {
" --system[=BOOL] Run as system-wide instance\n"
" -D, --daemonize[=BOOL] Daemonize after startup\n"
" --fail[=BOOL] Quit when startup fails\n"
- " --high-priority[=BOOL] Try to set high process priority\n"
- " (only available as root)\n"
+ " --high-priority[=BOOL] Try to set high nice level\n"
+ " (only available as root, when SUID or\n"
+ " with elevated RLIMIT_NICE)\n"
+ " --realtime[=BOOL] Try to enable realtime scheduling\n"
+ " (only available as root, when SUID or\n"
+ " with elevated RLIMIT_RTPRIO)\n"
" --disallow-module-loading[=BOOL] Disallow module loading after startup\n"
" --exit-idle-time=SECS Terminate the daemon when idle and this\n"
" time passed\n"
@@ -138,7 +145,7 @@ void pa_cmdline_help(const char *argv0) {
" --log-target={auto,syslog,stderr} Specify the log target\n"
" -p, --dl-search-path=PATH Set the search path for dynamic shared\n"
" objects (plugins)\n"
- " --resample-method=[METHOD] Use the specified resampling method\n"
+ " --resample-method=METHOD Use the specified resampling method\n"
" (See --dump-resample-methods for\n"
" possible values)\n"
" --use-pid-file[=BOOL] Create a PID file\n"
@@ -159,7 +166,7 @@ void pa_cmdline_help(const char *argv0) {
int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d) {
pa_strbuf *buf = NULL;
int c;
-
+
pa_assert(conf);
pa_assert(argc > 0);
pa_assert(argv);
@@ -195,12 +202,17 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
case ARG_CLEANUP_SHM:
conf->cmd = PA_CMD_CLEANUP_SHM;
break;
-
+
case 'k':
case ARG_KILL:
conf->cmd = PA_CMD_KILL;
break;
+ case ARG_START:
+ conf->cmd = PA_CMD_START;
+ conf->daemonize = TRUE;
+ break;
+
case ARG_CHECK:
conf->cmd = PA_CMD_CHECK;
break;
@@ -224,14 +236,14 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
case ARG_DAEMONIZE:
case 'D':
- if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->daemonize = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--daemonize expects boolean argument");
goto fail;
}
break;
case ARG_FAIL:
- if ((conf->fail = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->fail = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--fail expects boolean argument");
goto fail;
}
@@ -253,21 +265,28 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
break;
case ARG_HIGH_PRIORITY:
- if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->high_priority = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--high-priority expects boolean argument");
goto fail;
}
break;
+ case ARG_REALTIME:
+ if ((conf->realtime_scheduling = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
+ pa_log("--realtime expects boolean argument");
+ goto fail;
+ }
+ break;
+
case ARG_DISALLOW_MODULE_LOADING:
- if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->disallow_module_loading = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--disallow-module-loading expects boolean argument");
goto fail;
}
break;
case ARG_USE_PID_FILE:
- if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->use_pid_file = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--use-pid-file expects boolean argument");
goto fail;
}
@@ -280,8 +299,7 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
break;
case 'n':
- pa_xfree(conf->default_script_file);
- conf->default_script_file = NULL;
+ conf->load_default_script_file = FALSE;
break;
case ARG_LOG_TARGET:
@@ -311,21 +329,21 @@ int pa_cmdline_parse(pa_daemon_conf *conf, int argc, char *const argv [], int *d
break;
case ARG_SYSTEM:
- if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->system_instance = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--system expects boolean argument");
goto fail;
}
break;
case ARG_NO_CPU_LIMIT:
- if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->no_cpu_limit = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--no-cpu-limit expects boolean argument");
goto fail;
}
break;
case ARG_DISABLE_SHM:
- if ((conf->disable_shm = optarg ? pa_parse_boolean(optarg) : 1) < 0) {
+ if ((conf->disable_shm = optarg ? pa_parse_boolean(optarg) : TRUE) < 0) {
pa_log("--disable-shm expects boolean argument");
goto fail;
}
diff --git a/src/daemon/cmdline.h b/src/daemon/cmdline.h
index 18418894..fd72a6d3 100644
--- a/src/daemon/cmdline.h
+++ b/src/daemon/cmdline.h
@@ -1,8 +1,6 @@
#ifndef foocmdlinehfoo
#define foocmdlinehfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/cpulimit.c b/src/daemon/cpulimit.c
index a61f43eb..42a71f7e 100644
--- a/src/daemon/cpulimit.c
+++ b/src/daemon/cpulimit.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -82,7 +80,7 @@ static pa_io_event *io_event = NULL;
static struct sigaction sigaction_prev;
/* Nonzero after pa_cpu_limit_init() */
-static int installed = 0;
+static pa_bool_t installed = FALSE;
/* The current state of operation */
static enum {
@@ -113,6 +111,9 @@ static void write_err(const char *p) {
/* The signal handler, called on every SIGXCPU */
static void signal_handler(int sig) {
+ int saved_errno;
+
+ saved_errno = errno;
pa_assert(sig == SIGXCPU);
if (phase == PHASE_IDLE) {
@@ -148,8 +149,10 @@ static void signal_handler(int sig) {
} else if (phase == PHASE_SOFT) {
write_err("Hard CPU time limit exhausted, terminating forcibly.\n");
- _exit(1); /* Forced exit */
+ abort(); /* Forced exit */
}
+
+ errno = saved_errno;
}
/* Callback for IO events on the FIFO */
@@ -160,7 +163,7 @@ static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags
pa_assert(f == PA_IO_EVENT_INPUT);
pa_assert(e == io_event);
pa_assert(fd == the_pipe[0]);
-
+
pa_read(the_pipe[0], &c, sizeof(c), NULL);
m->quit(m, 1); /* Quit the main loop */
}
@@ -168,7 +171,7 @@ static void callback(pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags
/* Initializes CPU load limiter */
int pa_cpu_limit_init(pa_mainloop_api *m) {
struct sigaction sa;
-
+
pa_assert(m);
pa_assert(!api);
pa_assert(!io_event);
@@ -205,7 +208,7 @@ int pa_cpu_limit_init(pa_mainloop_api *m) {
return -1;
}
- installed = 1;
+ installed = TRUE;
reset_cpu_time(CPUTIME_INTERVAL_SOFT);
@@ -226,7 +229,7 @@ void pa_cpu_limit_done(void) {
if (installed) {
pa_assert_se(sigaction(SIGXCPU, &sigaction_prev, NULL) >= 0);
- installed = 0;
+ installed = FALSE;
}
}
diff --git a/src/daemon/cpulimit.h b/src/daemon/cpulimit.h
index 271109b4..cb9a123d 100644
--- a/src/daemon/cpulimit.h
+++ b/src/daemon/cpulimit.h
@@ -1,8 +1,6 @@
#ifndef foocpulimithfoo
#define foocpulimithfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/daemon-conf.c b/src/daemon/daemon-conf.c
index 825101c7..9ac40901 100644
--- a/src/daemon/daemon-conf.c
+++ b/src/daemon/daemon-conf.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -30,8 +28,10 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
+#include <sched.h>
#include <pulse/xmalloc.h>
+#include <pulse/timeval.h>
#include <pulsecore/core-error.h>
#include <pulsecore/core-util.h>
@@ -44,6 +44,8 @@
#define DEFAULT_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "default.pa"
#define DEFAULT_SCRIPT_FILE_USER PA_PATH_SEP "default.pa"
+#define DEFAULT_SYSTEM_SCRIPT_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "system.pa"
+
#define DEFAULT_CONFIG_FILE PA_DEFAULT_CONFIG_DIR PA_PATH_SEP "daemon.conf"
#define DEFAULT_CONFIG_FILE_USER PA_PATH_SEP "daemon.conf"
@@ -53,51 +55,71 @@
static const pa_daemon_conf default_conf = {
.cmd = PA_CMD_DAEMON,
- .daemonize = 0,
- .fail = 1,
- .high_priority = 0,
- .disallow_module_loading = 0,
+ .daemonize = FALSE,
+ .fail = TRUE,
+ .high_priority = TRUE,
+ .nice_level = -11,
+ .realtime_scheduling = FALSE,
+ .realtime_priority = 5, /* Half of JACK's default rtprio */
+ .disallow_module_loading = FALSE,
.exit_idle_time = -1,
.module_idle_time = 20,
.scache_idle_time = 20,
.auto_log_target = 1,
.script_commands = NULL,
.dl_search_path = NULL,
+ .load_default_script_file = TRUE,
.default_script_file = NULL,
.log_target = PA_LOG_SYSLOG,
.log_level = PA_LOG_NOTICE,
.resample_method = PA_RESAMPLER_AUTO,
+ .disable_remixing = FALSE,
.config_file = NULL,
- .use_pid_file = 1,
- .system_instance = 0,
- .no_cpu_limit = 0,
- .disable_shm = 0,
+ .use_pid_file = TRUE,
+ .system_instance = FALSE,
+ .no_cpu_limit = FALSE,
+ .disable_shm = FALSE,
.default_n_fragments = 4,
.default_fragment_size_msec = 25,
.default_sample_spec = { .format = PA_SAMPLE_S16NE, .rate = 44100, .channels = 2 }
#ifdef HAVE_SYS_RESOURCE_H
- , .rlimit_as = { .value = 0, .is_set = 0 },
- .rlimit_core = { .value = 0, .is_set = 0 },
- .rlimit_data = { .value = 0, .is_set = 0 },
- .rlimit_fsize = { .value = 0, .is_set = 0 },
- .rlimit_nofile = { .value = 256, .is_set = 1 },
- .rlimit_stack = { .value = 0, .is_set = 0 }
+ ,.rlimit_fsize = { .value = 0, .is_set = FALSE },
+ .rlimit_data = { .value = 0, .is_set = FALSE },
+ .rlimit_stack = { .value = 0, .is_set = FALSE },
+ .rlimit_core = { .value = 0, .is_set = FALSE },
+ .rlimit_rss = { .value = 0, .is_set = FALSE }
#ifdef RLIMIT_NPROC
- , .rlimit_nproc = { .value = 0, .is_set = 0 }
+ ,.rlimit_nproc = { .value = 0, .is_set = FALSE }
#endif
+ ,.rlimit_nofile = { .value = 256, .is_set = TRUE }
#ifdef RLIMIT_MEMLOCK
- , .rlimit_memlock = { .value = 16384, .is_set = 1 }
+ ,.rlimit_memlock = { .value = 0, .is_set = FALSE }
+#endif
+ ,.rlimit_as = { .value = 0, .is_set = FALSE }
+#ifdef RLIMIT_LOCKS
+ ,.rlimit_locks = { .value = 0, .is_set = FALSE }
+#endif
+#ifdef RLIMIT_SIGPENDING
+ ,.rlimit_sigpending = { .value = 0, .is_set = FALSE }
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ ,.rlimit_msgqueue = { .value = 0, .is_set = FALSE }
+#endif
+#ifdef RLIMIT_NICE
+ ,.rlimit_nice = { .value = 31, .is_set = TRUE } /* nice level of -11 */
+#endif
+#ifdef RLIMIT_RTPRIO
+ ,.rlimit_rtprio = { .value = 9, .is_set = TRUE } /* One below JACK's default for the server */
+#endif
+#ifdef RLIMIT_RTTIME
+ ,.rlimit_rttime = { .value = PA_USEC_PER_SEC, .is_set = TRUE }
#endif
#endif
};
pa_daemon_conf* pa_daemon_conf_new(void) {
- FILE *f;
pa_daemon_conf *c = pa_xnewdup(pa_daemon_conf, &default_conf, 1);
- if ((f = pa_open_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE, &c->default_script_file, "r")))
- fclose(f);
-
c->dl_search_path = pa_xstrdup(PA_DLSEARCHPATH);
return c;
}
@@ -185,7 +207,7 @@ static int parse_log_target(const char *filename, unsigned line, const char *lva
static int parse_log_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
pa_daemon_conf *c = data;
-
+
pa_assert(filename);
pa_assert(lvalue);
pa_assert(rvalue);
@@ -271,7 +293,7 @@ static int parse_sample_rate(const char *filename, unsigned line, const char *lv
pa_assert(rvalue);
pa_assert(data);
- if (pa_atoi(rvalue, &r) < 0 || r > PA_RATE_MAX || r <= 0) {
+ if (pa_atoi(rvalue, &r) < 0 || r > (int32_t) PA_RATE_MAX || r <= 0) {
pa_log("[%s:%u] Invalid sample rate '%s'.", filename, line, rvalue);
return -1;
}
@@ -289,11 +311,11 @@ static int parse_sample_channels(const char *filename, unsigned line, const char
pa_assert(rvalue);
pa_assert(data);
- if (pa_atoi(rvalue, &n) < 0 || n > PA_CHANNELS_MAX || n <= 0) {
+ if (pa_atoi(rvalue, &n) < 0 || n > (int32_t) PA_CHANNELS_MAX || n <= 0) {
pa_log("[%s:%u] Invalid sample channels '%s'.", filename, line, rvalue);
return -1;
}
-
+
c->default_sample_spec.channels = (uint8_t) n;
return 0;
}
@@ -334,6 +356,42 @@ static int parse_fragment_size_msec(const char *filename, unsigned line, const c
return 0;
}
+static int parse_nice_level(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+ pa_daemon_conf *c = data;
+ int32_t level;
+
+ pa_assert(filename);
+ pa_assert(lvalue);
+ pa_assert(rvalue);
+ pa_assert(data);
+
+ if (pa_atoi(rvalue, &level) < 0 || level < -20 || level > 19) {
+ pa_log("[%s:%u] Invalid nice level '%s'.", filename, line, rvalue);
+ return -1;
+ }
+
+ c->nice_level = (int) level;
+ return 0;
+}
+
+static int parse_rtprio(const char *filename, unsigned line, const char *lvalue, const char *rvalue, void *data, PA_GCC_UNUSED void *userdata) {
+ pa_daemon_conf *c = data;
+ int32_t rtprio;
+
+ pa_assert(filename);
+ pa_assert(lvalue);
+ pa_assert(rvalue);
+ pa_assert(data);
+
+ if (pa_atoi(rvalue, &rtprio) < 0 || rtprio < sched_get_priority_min(SCHED_FIFO) || rtprio > sched_get_priority_max(SCHED_FIFO)) {
+ pa_log("[%s:%u] Invalid realtime priority '%s'.", filename, line, rvalue);
+ return -1;
+ }
+
+ c->realtime_priority = (int) rtprio;
+ return 0;
+}
+
int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
int r = -1;
FILE *f = NULL;
@@ -342,38 +400,62 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
{ "daemonize", pa_config_parse_bool, NULL },
{ "fail", pa_config_parse_bool, NULL },
{ "high-priority", pa_config_parse_bool, NULL },
+ { "realtime-scheduling", pa_config_parse_bool, NULL },
{ "disallow-module-loading", pa_config_parse_bool, NULL },
+ { "use-pid-file", pa_config_parse_bool, NULL },
+ { "system-instance", pa_config_parse_bool, NULL },
+ { "no-cpu-limit", pa_config_parse_bool, NULL },
+ { "disable-shm", pa_config_parse_bool, NULL },
{ "exit-idle-time", pa_config_parse_int, NULL },
{ "module-idle-time", pa_config_parse_int, NULL },
{ "scache-idle-time", pa_config_parse_int, NULL },
+ { "realtime-priority", parse_rtprio, NULL },
{ "dl-search-path", pa_config_parse_string, NULL },
{ "default-script-file", pa_config_parse_string, NULL },
{ "log-target", parse_log_target, NULL },
{ "log-level", parse_log_level, NULL },
{ "verbose", parse_log_level, NULL },
{ "resample-method", parse_resample_method, NULL },
- { "use-pid-file", pa_config_parse_bool, NULL },
- { "system-instance", pa_config_parse_bool, NULL },
- { "no-cpu-limit", pa_config_parse_bool, NULL },
- { "disable-shm", pa_config_parse_bool, NULL },
{ "default-sample-format", parse_sample_format, NULL },
{ "default-sample-rate", parse_sample_rate, NULL },
{ "default-sample-channels", parse_sample_channels, NULL },
{ "default-fragments", parse_fragments, NULL },
- { "default-fragment-size-msec", parse_fragment_size_msec, NULL },
+ { "default-fragment-size-msec", parse_fragment_size_msec, NULL },
+ { "nice-level", parse_nice_level, NULL },
+ { "disable-remixing", pa_config_parse_bool, NULL },
+ { "load-default-script-file", pa_config_parse_bool, NULL },
#ifdef HAVE_SYS_RESOURCE_H
- { "rlimit-as", parse_rlimit, NULL },
- { "rlimit-core", parse_rlimit, NULL },
- { "rlimit-data", parse_rlimit, NULL },
{ "rlimit-fsize", parse_rlimit, NULL },
- { "rlimit-nofile", parse_rlimit, NULL },
+ { "rlimit-data", parse_rlimit, NULL },
{ "rlimit-stack", parse_rlimit, NULL },
+ { "rlimit-core", parse_rlimit, NULL },
+ { "rlimit-rss", parse_rlimit, NULL },
+ { "rlimit-nofile", parse_rlimit, NULL },
+ { "rlimit-as", parse_rlimit, NULL },
#ifdef RLIMIT_NPROC
{ "rlimit-nproc", parse_rlimit, NULL },
#endif
#ifdef RLIMIT_MEMLOCK
{ "rlimit-memlock", parse_rlimit, NULL },
#endif
+#ifdef RLIMIT_LOCKS
+ { "rlimit-locks", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_SIGPENDING
+ { "rlimit-sigpending", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ { "rlimit-msgqueue", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_NICE
+ { "rlimit-nice", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_RTPRIO
+ { "rlimit-rtprio", parse_rlimit, NULL },
+#endif
+#ifdef RLIMIT_RTTIME
+ { "rlimit-rttime", parse_rlimit, NULL },
+#endif
#endif
{ NULL, NULL, NULL },
};
@@ -381,40 +463,89 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
table[0].data = &c->daemonize;
table[1].data = &c->fail;
table[2].data = &c->high_priority;
- table[3].data = &c->disallow_module_loading;
- table[4].data = &c->exit_idle_time;
- table[5].data = &c->module_idle_time;
- table[6].data = &c->scache_idle_time;
- table[7].data = &c->dl_search_path;
- table[8].data = &c->default_script_file;
- table[9].data = c;
- table[10].data = c;
- table[11].data = c;
+ table[3].data = &c->realtime_scheduling;
+ table[4].data = &c->disallow_module_loading;
+ table[5].data = &c->use_pid_file;
+ table[6].data = &c->system_instance;
+ table[7].data = &c->no_cpu_limit;
+ table[8].data = &c->disable_shm;
+ table[9].data = &c->exit_idle_time;
+ table[10].data = &c->module_idle_time;
+ table[11].data = &c->scache_idle_time;
table[12].data = c;
- table[13].data = &c->use_pid_file;
- table[14].data = &c->system_instance;
- table[15].data = &c->no_cpu_limit;
- table[16].data = &c->disable_shm;
+ table[13].data = &c->dl_search_path;
+ table[14].data = &c->default_script_file;
+ table[15].data = c;
+ table[16].data = c;
table[17].data = c;
table[18].data = c;
table[19].data = c;
table[20].data = c;
table[21].data = c;
+ table[22].data = c;
+ table[23].data = c;
+ table[24].data = c;
+ table[25].data = &c->disable_remixing;
+ table[26].data = &c->load_default_script_file;
#ifdef HAVE_SYS_RESOURCE_H
- table[22].data = &c->rlimit_as;
- table[23].data = &c->rlimit_core;
- table[24].data = &c->rlimit_data;
- table[25].data = &c->rlimit_fsize;
- table[26].data = &c->rlimit_nofile;
- table[27].data = &c->rlimit_stack;
+ table[27].data = &c->rlimit_fsize;
+ table[28].data = &c->rlimit_data;
+ table[29].data = &c->rlimit_stack;
+ table[30].data = &c->rlimit_as;
+ table[31].data = &c->rlimit_core;
+ table[32].data = &c->rlimit_nofile;
+ table[33].data = &c->rlimit_as;
#ifdef RLIMIT_NPROC
- table[28].data = &c->rlimit_nproc;
+ table[34].data = &c->rlimit_nproc;
#endif
+
#ifdef RLIMIT_MEMLOCK
#ifndef RLIMIT_NPROC
#error "Houston, we have a numbering problem!"
#endif
- table[29].data = &c->rlimit_memlock;
+ table[35].data = &c->rlimit_memlock;
+#endif
+
+#ifdef RLIMIT_LOCKS
+#ifndef RLIMIT_MEMLOCK
+#error "Houston, we have a numbering problem!"
+#endif
+ table[36].data = &c->rlimit_locks;
+#endif
+
+#ifdef RLIMIT_SIGPENDING
+#ifndef RLIMIT_LOCKS
+#error "Houston, we have a numbering problem!"
+#endif
+ table[37].data = &c->rlimit_sigpending;
+#endif
+
+#ifdef RLIMIT_MSGQUEUE
+#ifndef RLIMIT_SIGPENDING
+#error "Houston, we have a numbering problem!"
+#endif
+ table[38].data = &c->rlimit_msgqueue;
+#endif
+
+#ifdef RLIMIT_NICE
+#ifndef RLIMIT_MSGQUEUE
+#error "Houston, we have a numbering problem!"
+#endif
+ table[39].data = &c->rlimit_nice;
+#endif
+
+#ifdef RLIMIT_RTPRIO
+#ifndef RLIMIT_NICE
+#error "Houston, we have a numbering problem!"
+#endif
+ table[40].data = &c->rlimit_rtprio;
+#endif
+
+#ifdef RLIMIT_RTTIME
+#ifndef RLIMIT_RTTIME
+#error "Houston, we have a numbering problem!"
+#endif
+ table[41].data = &c->rlimit_rttime;
#endif
#endif
@@ -423,10 +554,10 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
f = filename ?
fopen(c->config_file = pa_xstrdup(filename), "r") :
- pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file, "r");
+ pa_open_config_file(DEFAULT_CONFIG_FILE, DEFAULT_CONFIG_FILE_USER, ENV_CONFIG_FILE, &c->config_file);
if (!f && errno != ENOENT) {
- pa_log_warn("Failed to open configuration file '%s': %s", c->config_file, pa_cstrerror(errno));
+ pa_log_warn("Failed to open configuration file: %s", pa_cstrerror(errno));
goto finish;
}
@@ -441,6 +572,7 @@ finish:
int pa_daemon_conf_env(pa_daemon_conf *c) {
char *e;
+ pa_assert(c);
if ((e = getenv(ENV_DL_SEARCH_PATH))) {
pa_xfree(c->dl_search_path);
@@ -454,6 +586,35 @@ int pa_daemon_conf_env(pa_daemon_conf *c) {
return 0;
}
+const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c) {
+ pa_assert(c);
+
+ if (!c->default_script_file) {
+ if (c->system_instance)
+ c->default_script_file = pa_find_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE);
+ else
+ c->default_script_file = pa_find_config_file(DEFAULT_SCRIPT_FILE, DEFAULT_SCRIPT_FILE_USER, ENV_SCRIPT_FILE);
+ }
+
+ return c->default_script_file;
+}
+
+FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c) {
+ FILE *f;
+ pa_assert(c);
+
+ if (!c->default_script_file) {
+ if (c->system_instance)
+ f = pa_open_config_file(DEFAULT_SYSTEM_SCRIPT_FILE, NULL, ENV_SCRIPT_FILE, &c->default_script_file);
+ 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");
+
+ return f;
+}
+
+
static const char* const log_level_to_string[] = {
[PA_LOG_DEBUG] = "debug",
[PA_LOG_INFO] = "info",
@@ -474,40 +635,64 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
pa_assert(c->log_level <= PA_LOG_LEVEL_MAX);
- pa_strbuf_printf(s, "daemonize = %i\n", !!c->daemonize);
- pa_strbuf_printf(s, "fail = %i\n", !!c->fail);
- pa_strbuf_printf(s, "high-priority = %i\n", !!c->high_priority);
- pa_strbuf_printf(s, "disallow-module-loading = %i\n", !!c->disallow_module_loading);
+ pa_strbuf_printf(s, "daemonize = %s\n", pa_yes_no(c->daemonize));
+ pa_strbuf_printf(s, "fail = %s\n", pa_yes_no(c->fail));
+ pa_strbuf_printf(s, "high-priority = %s\n", pa_yes_no(c->high_priority));
+ 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, "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));
pa_strbuf_printf(s, "exit-idle-time = %i\n", c->exit_idle_time);
pa_strbuf_printf(s, "module-idle-time = %i\n", c->module_idle_time);
pa_strbuf_printf(s, "scache-idle-time = %i\n", c->scache_idle_time);
- pa_strbuf_printf(s, "dl-search-path = %s\n", c->dl_search_path ? c->dl_search_path : "");
- pa_strbuf_printf(s, "default-script-file = %s\n", c->default_script_file);
+ pa_strbuf_printf(s, "dl-search-path = %s\n", pa_strempty(c->dl_search_path));
+ pa_strbuf_printf(s, "default-script-file = %s\n", pa_strempty(pa_daemon_conf_get_default_script_file(c)));
+ pa_strbuf_printf(s, "load-default-script-file = %s\n", pa_yes_no(c->load_default_script_file));
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, "use-pid-file = %i\n", c->use_pid_file);
- pa_strbuf_printf(s, "system-instance = %i\n", !!c->system_instance);
- pa_strbuf_printf(s, "no-cpu-limit = %i\n", !!c->no_cpu_limit);
- pa_strbuf_printf(s, "disable-shm = %i\n", !!c->disable_shm);
+ pa_strbuf_printf(s, "disable-remixing = %s\n", pa_yes_no(c->disable_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-fragments = %u\n", c->default_n_fragments);
pa_strbuf_printf(s, "default-fragment-size-msec = %u\n", c->default_fragment_size_msec);
#ifdef HAVE_SYS_RESOURCE_H
- pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
- pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1);
- pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
pa_strbuf_printf(s, "rlimit-fsize = %li\n", c->rlimit_fsize.is_set ? (long int) c->rlimit_fsize.value : -1);
- pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1);
+ pa_strbuf_printf(s, "rlimit-data = %li\n", c->rlimit_data.is_set ? (long int) c->rlimit_data.value : -1);
pa_strbuf_printf(s, "rlimit-stack = %li\n", c->rlimit_stack.is_set ? (long int) c->rlimit_stack.value : -1);
+ pa_strbuf_printf(s, "rlimit-core = %li\n", c->rlimit_core.is_set ? (long int) c->rlimit_core.value : -1);
+ pa_strbuf_printf(s, "rlimit-as = %li\n", c->rlimit_as.is_set ? (long int) c->rlimit_as.value : -1);
+ pa_strbuf_printf(s, "rlimit-rss = %li\n", c->rlimit_rss.is_set ? (long int) c->rlimit_rss.value : -1);
#ifdef RLIMIT_NPROC
pa_strbuf_printf(s, "rlimit-nproc = %li\n", c->rlimit_nproc.is_set ? (long int) c->rlimit_nproc.value : -1);
#endif
+ pa_strbuf_printf(s, "rlimit-nofile = %li\n", c->rlimit_nofile.is_set ? (long int) c->rlimit_nofile.value : -1);
#ifdef RLIMIT_MEMLOCK
pa_strbuf_printf(s, "rlimit-memlock = %li\n", c->rlimit_memlock.is_set ? (long int) c->rlimit_memlock.value : -1);
#endif
+#ifdef RLIMIT_LOCKS
+ pa_strbuf_printf(s, "rlimit-locks = %li\n", c->rlimit_locks.is_set ? (long int) c->rlimit_locks.value : -1);
+#endif
+#ifdef RLIMIT_SIGPENDING
+ pa_strbuf_printf(s, "rlimit-sigpending = %li\n", c->rlimit_sigpending.is_set ? (long int) c->rlimit_sigpending.value : -1);
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ pa_strbuf_printf(s, "rlimit-msgqueue = %li\n", c->rlimit_msgqueue.is_set ? (long int) c->rlimit_msgqueue.value : -1);
+#endif
+#ifdef RLIMIT_NICE
+ pa_strbuf_printf(s, "rlimit-nice = %li\n", c->rlimit_nice.is_set ? (long int) c->rlimit_nice.value : -1);
+#endif
+#ifdef RLIMIT_RTPRIO
+ pa_strbuf_printf(s, "rlimit-rtprio = %li\n", c->rlimit_rtprio.is_set ? (long int) c->rlimit_rtprio.value : -1);
+#endif
+#ifdef RLIMIT_RTTIME
+ pa_strbuf_printf(s, "rlimit-rttime = %li\n", c->rlimit_rttime.is_set ? (long int) c->rlimit_rttime.value : -1);
+#endif
#endif
return pa_strbuf_tostring_free(s);
diff --git a/src/daemon/daemon-conf.h b/src/daemon/daemon-conf.h
index 4d37861d..be2fe1ab 100644
--- a/src/daemon/daemon-conf.h
+++ b/src/daemon/daemon-conf.h
@@ -1,8 +1,6 @@
#ifndef foodaemonconfhfoo
#define foodaemonconfhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -26,6 +24,8 @@
***/
#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
#include <pulse/sample.h>
#ifdef HAVE_SYS_RESOURCE_H
@@ -35,6 +35,7 @@
/* The actual command to execute */
typedef enum pa_daemon_conf_cmd {
PA_CMD_DAEMON, /* the default */
+ PA_CMD_START,
PA_CMD_HELP,
PA_CMD_VERSION,
PA_CMD_DUMP_CONF,
@@ -48,39 +49,62 @@ typedef enum pa_daemon_conf_cmd {
#ifdef HAVE_SYS_RESOURCE_H
typedef struct pa_rlimit {
rlim_t value;
- int is_set;
+ pa_bool_t is_set;
} pa_rlimit;
#endif
/* A structure containing configuration data for the PulseAudio server . */
typedef struct pa_daemon_conf {
pa_daemon_conf_cmd_t cmd;
- int daemonize,
+ pa_bool_t daemonize,
fail,
high_priority,
+ realtime_scheduling,
disallow_module_loading,
- exit_idle_time,
- module_idle_time,
- scache_idle_time,
- auto_log_target,
use_pid_file,
system_instance,
no_cpu_limit,
- disable_shm;
+ disable_shm,
+ disable_remixing,
+ load_default_script_file;
+ int exit_idle_time,
+ module_idle_time,
+ scache_idle_time,
+ auto_log_target,
+ realtime_priority,
+ nice_level,
+ resample_method;
char *script_commands, *dl_search_path, *default_script_file;
pa_log_target_t log_target;
pa_log_level_t log_level;
- int resample_method;
char *config_file;
#ifdef HAVE_SYS_RESOURCE_H
- pa_rlimit rlimit_as, rlimit_core, rlimit_data, rlimit_fsize, rlimit_nofile, rlimit_stack;
+ pa_rlimit rlimit_fsize, rlimit_data, rlimit_stack, rlimit_core, rlimit_rss, rlimit_nofile, rlimit_as;
#ifdef RLIMIT_NPROC
pa_rlimit rlimit_nproc;
#endif
#ifdef RLIMIT_MEMLOCK
pa_rlimit rlimit_memlock;
#endif
+#ifdef RLIMIT_LOCKS
+ pa_rlimit rlimit_locks;
+#endif
+#ifdef RLIMIT_SIGPENDING
+ pa_rlimit rlimit_sigpending;
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ pa_rlimit rlimit_msgqueue;
+#endif
+#ifdef RLIMIT_NICE
+ pa_rlimit rlimit_nice;
+#endif
+#ifdef RLIMIT_RTPRIO
+ pa_rlimit rlimit_rtprio;
+#endif
+#ifdef RLIMIT_RTTIME
+ pa_rlimit rlimit_rttime;
+#endif
#endif
unsigned default_n_fragments, default_fragment_size_msec;
@@ -110,4 +134,7 @@ 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);
+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);
+
#endif
diff --git a/src/daemon/daemon.conf.in b/src/daemon/daemon.conf.in
index 2132bf3d..dfabcfb2 100644
--- a/src/daemon/daemon.conf.in
+++ b/src/daemon/daemon.conf.in
@@ -1,5 +1,3 @@
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
@@ -17,94 +15,59 @@
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.
-## Configuration file for the pulseaudio daemon. Default values are
-## commented out. Use either ; or # for commenting
-
-# Extra verbositiy
-; verbose = 0
+## Configuration file for the PulseAudio daemon. See pulse-daemon.conf(5) for
+## more information. Default values a commented out. Use either ; or # for
+## commenting.
-## Daemonize after startup
-; daemonize = 0
+; daemonize = no
+; fail = yes
+; disallow-module-loading = no
+; use-pid-file = yes
+; system-instance = no
+; disable-shm = no
-## Quit if startup fails
-; fail = 1
+; high-priority = yes
+; nice-level = -11
-## Renice the daemon to level -15 and try to get SCHED_FIFO
-## scheduling. This a good idea if you hear annyoing noise in the
-## playback. However, this is a certain security issue, since it works
-## when called SUID root only. root is dropped immediately after gaining
-## the nice level and SCHED_FIFO scheduling on startup.
-; high-priority = 0
+; realtime-scheduling = no
+; realtime-priority = 5
-## Disallow module loading after startup
-; disallow-module-loading = 0
-
-## Terminate the daemon after the last client quit and this time
-## passed. Use a negative value to disable this feature.
; exit-idle-time = -1
-
-## Unload autoloaded modules after being idle for this time
; module-idle-time = 20
-
-## Unload autoloaded sample cache entries after being idle for this time
; scache-idle-time = 20
-## The path were to look for dynamic shared objects (DSOs aka
-## plugins). You may specify more than one path seperated by
-## colons.
-; dl-search-path = @PA_DLSEARCHPATH@
+; dl-search-path = (depends on architecture)
-## The default script file to load. Specify an empty string for not
-## loading a default script file. The
+; load-defaul-script-file = yes
; default-script-file = @PA_DEFAULT_CONFIG_FILE@
-## The default log target. Use either "stderr", "syslog" or
-## "auto". The latter is equivalent to "sylog" in case daemonize is
-## true, otherwise to "stderr".
; log-target = auto
+; log-level = notice
-## The resampling algorithm to use. Use one of src-sinc-best-quality,
-## src-sinc-medium-quality, src-sinc-fastest, src-zero-order-hold,
-## src-linear, trivial. See the documentation of libsamplerate for an
-## explanation for the different methods. The method 'trivial' is the
-## only algorithm implemented without usage of floating point
-## numbers. If you're tight on CPU consider using this. On the other
-## hand it has the worst quality of all.
-; resample-method = sinc-fastest
-
-## Create a PID file in /tmp/pulseaudio-$USER/pid. Of this is enabled
-## you may use commands like "pulseaudio --kill" or "pulseaudio
-## --check". If you are planning to start more than one pulseaudio
-## process per user, you better disable this option since it
-## effectively disables multiple instances.
-; use-pid-file = 1
+; resample-method = speex-float-3
+; disable-remixing = no
-## Do not install the CPU load limit, even on platforms where it is
-## supported. This option is useful when debugging/profiling
-## PulseAudio to disable disturbing SIGXCPU signals.
-; no-cpu-limit = 0
+; no-cpu-limit = no
-## Run the daemon as system-wide instance, requires root priviliges
-; system-instance = 0
-
-## Resource limits, see getrlimit(2) for more information
-; rlimit-as = -1
-; rlimit-core = -1
-; rlimit-data = -1
; rlimit-fsize = -1
-; rlimit-nofile = 256
+; rlimit-data = -1
; rlimit-stack = -1
+; rlimit-core = -1
+; rlimit-as = -1
+; rlimit-rss = -1
; rlimit-nproc = -1
-; rlimit-memlock = 16384
-
-## Disable shared memory data transfer
-; disable-shm = 0
+; rlimit-nofile = 256
+; rlimit-memlock = -1
+; rlimit-locks = -1
+; rlimit-sigpending = -1
+; rlimit-msgqueue = -1
+; rlimit-nice = 31
+; rlimit-rtprio = 9
+; rlimit-rtttime = 1000000
-## Default sample format
; default-sample-format = s16le
; default-sample-rate = 44100
; default-sample-channels = 2
-## Default fragment settings, for device drivers that need this
; default-fragments = 4
; default-fragment-size-msec = 25
diff --git a/src/daemon/default.pa.in b/src/daemon/default.pa.in
index 597993c4..aad9f5d6 100755
--- a/src/daemon/default.pa.in
+++ b/src/daemon/default.pa.in
@@ -37,7 +37,7 @@ load-sample-lazy pulse-hotplug /usr/share/sounds/startup3.wav
#load-module module-pipe-sink
### Automatically load driver modules depending on the hardware available
-.ifexists @PA_DLSEARCHPATH@/module-hal-detect@PA_SOEXT@
+.ifexists module-hal-detect@PA_SOEXT@
load-module module-hal-detect
.else
### Alternatively use the static hardware detection module (for systems that
@@ -46,7 +46,9 @@ load-module module-detect
.endif
### Load several protocols
+.ifexists module-esound-protocol-unix@PA_SOEXT@
load-module module-esound-protocol-unix
+.endif
load-module module-native-protocol-unix
### Network access (may be configured with paprefs, so leave this commented
@@ -72,27 +74,41 @@ load-module module-default-device-restore
### connected to dies, similar for sources
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
+
### Automatically suspend sinks/sources that become idle for too long
load-module module-suspend-on-idle
### Load X11 bell module
-#load-module module-x11-bell sample=x11-bell
-
-### Publish connection data in the X11 root window
-.ifexists @PA_DLSEARCHPATH@/module-x11-publish@PA_SOEXT@
-load-module module-x11-publish
-.endif
+#load-module module-x11-bell sample=bell-windowing-system
### Register ourselves in the X11 session manager
# Deactivated by default, to avoid deadlock when PA is started as esd from gnome-session
# Instead we load this via /etc/xdg/autostart/ and "pactl load-module" now
-# load-module module-x11-xsmp
+#load-module module-x11-xsmp
+
+### If autoexit on idle is enabled we want to make sure we only quit
+### when no local session needs us anymore.
+load-module module-console-kit
+
+### Enable positioned event sounds
+load-module module-position-event-sounds
### Load additional modules from GConf settings. This can be configured with the paprefs tool.
### Please keep in mind that the modules configured by paprefs might conflict with manually
### loaded modules.
-.ifexists @PA_DLSEARCHPATH@/module-gconf@PA_SOEXT@
+.ifexists module-gconf@PA_SOEXT@
+.nofail
load-module module-gconf
+.fail
+.endif
+
+### Publish connection data in the X11 root window
+.ifexists module-x11-publish@PA_SOEXT@
+.nofail
+load-module module-x11-publish
+.fail
.endif
### Make some devices default
diff --git a/src/daemon/dumpmodules.c b/src/daemon/dumpmodules.c
index 01547a30..cd6866aa 100644
--- a/src/daemon/dumpmodules.c
+++ b/src/daemon/dumpmodules.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -44,7 +42,7 @@
static void short_info(const char *name, PA_GCC_UNUSED const char *path, pa_modinfo *i) {
pa_assert(name);
pa_assert(i);
-
+
printf("%-40s%s\n", name, i->description ? i->description : "n/a");
}
@@ -71,6 +69,7 @@ static void long_info(const char *name, const char *path, pa_modinfo *i) {
printf("Author: %s\n", i->author);
if (i->usage)
printf("Usage: %s\n", i->usage);
+ printf("Load Once: %s\n", pa_yes_no(i->load_once));
}
if (path)
@@ -81,7 +80,7 @@ static void show_info(const char *name, const char *path, void (*info)(const cha
pa_modinfo *i;
pa_assert(name);
-
+
if ((i = pa_modinfo_get_by_name(path ? path : name))) {
info(name, path, i);
pa_modinfo_free(i);
@@ -128,7 +127,7 @@ static int callback(const char *path, lt_ptr data) {
void pa_dump_modules(pa_daemon_conf *c, int argc, char * const argv[]) {
pa_assert(c);
-
+
if (argc > 0) {
int i;
for (i = 0; i < argc; i++)
diff --git a/src/daemon/dumpmodules.h b/src/daemon/dumpmodules.h
index ab2ddb64..c49a5eda 100644
--- a/src/daemon/dumpmodules.h
+++ b/src/daemon/dumpmodules.h
@@ -1,8 +1,6 @@
#ifndef foodumpmoduleshfoo
#define foodumpmoduleshfoo
-/* $Id*/
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/esdcompat.in b/src/daemon/esdcompat.in
index 942389d2..66501803 100755
--- a/src/daemon/esdcompat.in
+++ b/src/daemon/esdcompat.in
@@ -1,7 +1,5 @@
#!/bin/sh
-# $Id$
-#
# This file is part of PulseAudio.
#
# PulseAudio is free software; you can redistribute it and/or modify
diff --git a/src/daemon/ltdl-bind-now.c b/src/daemon/ltdl-bind-now.c
index f5347db3..b1770674 100644
--- a/src/daemon/ltdl-bind-now.c
+++ b/src/daemon/ltdl-bind-now.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -34,6 +32,11 @@
#include <sys/dl.h>
#endif
+#ifndef HAVE_STRUCT_LT_USER_DLLOADER
+/* Only used with ltdl 2.2 */
+#include <string.h>
+#endif
+
#include <ltdl.h>
#include <pulsecore/macro.h>
@@ -85,7 +88,11 @@ static const char *libtool_get_error(void) {
to set $LT_BIND_NOW before starting the pulsaudio binary.
*/
+#ifndef HAVE_LT_DLADVISE
static lt_module bind_now_open(lt_user_data d, const char *fname) {
+#else
+ static lt_module bind_now_open(lt_user_data d, const char *fname, lt_dladvise advise) {
+#endif
lt_module m;
pa_assert(fname);
@@ -115,7 +122,7 @@ static lt_ptr bind_now_find_sym(lt_user_data d, lt_module m, const char *symbol)
pa_assert(m);
pa_assert(symbol);
-
+
if (!(ptr = dlsym(m, symbol))) {
libtool_set_error(dlerror());
return NULL;
@@ -129,26 +136,54 @@ static lt_ptr bind_now_find_sym(lt_user_data d, lt_module m, const char *symbol)
void pa_ltdl_init(void) {
#ifdef PA_BIND_NOW
+# ifdef HAVE_STRUCT_LT_USER_DLLOADER
lt_dlloader *place;
static const struct lt_user_dlloader loader = {
.module_open = bind_now_open,
.module_close = bind_now_close,
.find_sym = bind_now_find_sym
};
+# else
+ static const lt_dlvtable *dlopen_loader;
+ static lt_dlvtable bindnow_loader;
+# endif
#endif
-
- pa_assert_se(lt_dlinit() == 0);
+
+ pa_assert_se(lt_dlinit() == 0);
pa_assert_se(libtool_mutex = pa_mutex_new(TRUE, FALSE));
+#ifdef HAVE_LT_DLMUTEX_REGISTER
pa_assert_se(lt_dlmutex_register(libtool_lock, libtool_unlock, libtool_set_error, libtool_get_error) == 0);
+#endif
#ifdef PA_BIND_NOW
+# ifdef HAVE_STRUCT_LT_USER_DLLOADER
if (!(place = lt_dlloader_find("dlopen")))
place = lt_dlloader_next(NULL);
-
+
/* Add our BIND_NOW loader as the default module loader. */
if (lt_dlloader_add(place, &loader, "bind-now-loader") != 0)
pa_log_warn("Failed to add bind-now-loader.");
+# else
+ /* Already initialised */
+ if ( dlopen_loader != NULL ) return;
+
+ if (!(dlopen_loader = lt_dlloader_find("dlopen"))) {
+ pa_log_warn("Failed to find original dlopen loader.");
+ return;
+ }
+
+ memcpy(&bindnow_loader, dlopen_loader, sizeof(bindnow_loader));
+ bindnow_loader.name = "bind-now-loader";
+ bindnow_loader.module_open = bind_now_open;
+ bindnow_loader.module_close = bind_now_close;
+ bindnow_loader.find_sym = bind_now_find_sym;
+ bindnow_loader.priority = LT_DLLOADER_PREPEND;
+
+ /* Add our BIND_NOW loader as the default module loader. */
+ if (lt_dlloader_add(&bindnow_loader) != 0)
+ pa_log_warn("Failed to add bind-now-loader.");
+# endif
#endif
}
diff --git a/src/daemon/ltdl-bind-now.h b/src/daemon/ltdl-bind-now.h
index e19c7bc1..f95d13b4 100644
--- a/src/daemon/ltdl-bind-now.h
+++ b/src/daemon/ltdl-bind-now.h
@@ -1,8 +1,6 @@
#ifndef foopulsecoreltdlbindnowhfoo
#define foopulsecoreltdlbindnowhfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 6c9f6627..14594416 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -1,5 +1,3 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
@@ -94,6 +92,9 @@
#include "dumpmodules.h"
#include "caps.h"
#include "ltdl-bind-now.h"
+#include "polkit.h"
+
+#define AUTOSPAWN_LOCK "autospawn.lock"
#ifdef HAVE_LIBWRAP
/* Only one instance of these variables */
@@ -114,7 +115,7 @@ static void message_cb(pa_mainloop_api*a, pa_time_event*e, PA_GCC_UNUSED const s
MSG msg;
struct timeval tvnext;
- while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT)
raise(SIGTERM);
else {
@@ -163,8 +164,6 @@ static void signal_callback(pa_mainloop_api*m, PA_GCC_UNUSED pa_signal_event *e,
}
}
-#define set_env(key, value) putenv(pa_sprintf_malloc("%s=%s", (key), (value)))
-
#if defined(HAVE_PWD_H) && defined(HAVE_GRP_H)
static int change_user(void) {
@@ -203,6 +202,13 @@ static int change_user(void) {
return -1;
}
+ if (pa_make_secure_dir(PA_SYSTEM_STATE_PATH, 0700, pw->pw_uid, gr->gr_gid) < 0) {
+ pa_log("Failed to create '%s': %s", PA_SYSTEM_STATE_PATH, pa_cstrerror(errno));
+ return -1;
+ }
+
+ /* We don't create the config dir here, because we don't need to write to it */
+
if (initgroups(PA_SYSTEM_USER, gr->gr_gid) != 0) {
pa_log("Failed to change group list: %s", pa_cstrerror(errno));
return -1;
@@ -240,13 +246,15 @@ static int change_user(void) {
return -1;
}
- set_env("USER", PA_SYSTEM_USER);
- set_env("LOGNAME", PA_SYSTEM_GROUP);
- set_env("HOME", PA_SYSTEM_RUNTIME_PATH);
+ 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() */
- set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH);
- set_env("PULSE_CONFIG_PATH", PA_SYSTEM_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);
pa_log_info("Successfully dropped root privileges.");
@@ -262,51 +270,57 @@ static int change_user(void) {
#endif /* HAVE_PWD_H && HAVE_GRP_H */
-static int create_runtime_dir(void) {
- char fn[PATH_MAX];
-
- pa_runtime_path(NULL, fn, sizeof(fn));
-
- /* This function is called only when the daemon is started in
- * per-user mode. We create the runtime directory somewhere in
- * /tmp/ with the current UID/GID */
-
- if (pa_make_secure_dir(fn, 0700, (uid_t)-1, (gid_t)-1) < 0) {
- pa_log("Failed to create '%s': %s", fn, pa_cstrerror(errno));
- return -1;
- }
-
- return 0;
-}
-
#ifdef HAVE_SYS_RESOURCE_H
-static void set_one_rlimit(const pa_rlimit *r, int resource, const char *name) {
+static int set_one_rlimit(const pa_rlimit *r, int resource, const char *name) {
struct rlimit rl;
pa_assert(r);
if (!r->is_set)
- return;
+ return 0;
rl.rlim_cur = rl.rlim_max = r->value;
- if (setrlimit(resource, &rl) < 0)
- pa_log_warn("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno));
+ if (setrlimit(resource, &rl) < 0) {
+ pa_log_info("setrlimit(%s, (%u, %u)) failed: %s", name, (unsigned) r->value, (unsigned) r->value, pa_cstrerror(errno));
+ return -1;
+ }
+
+ return 0;
}
static void set_all_rlimits(const pa_daemon_conf *conf) {
- set_one_rlimit(&conf->rlimit_as, RLIMIT_AS, "RLIMIT_AS");
- set_one_rlimit(&conf->rlimit_core, RLIMIT_CORE, "RLIMIT_CORE");
- set_one_rlimit(&conf->rlimit_data, RLIMIT_DATA, "RLIMIT_DATA");
set_one_rlimit(&conf->rlimit_fsize, RLIMIT_FSIZE, "RLIMIT_FSIZE");
- set_one_rlimit(&conf->rlimit_nofile, RLIMIT_NOFILE, "RLIMIT_NOFILE");
+ set_one_rlimit(&conf->rlimit_data, RLIMIT_DATA, "RLIMIT_DATA");
set_one_rlimit(&conf->rlimit_stack, RLIMIT_STACK, "RLIMIT_STACK");
+ set_one_rlimit(&conf->rlimit_core, RLIMIT_CORE, "RLIMIT_CORE");
+ set_one_rlimit(&conf->rlimit_rss, RLIMIT_RSS, "RLIMIT_RSS");
#ifdef RLIMIT_NPROC
set_one_rlimit(&conf->rlimit_nproc, RLIMIT_NPROC, "RLIMIT_NPROC");
#endif
+ set_one_rlimit(&conf->rlimit_nofile, RLIMIT_NOFILE, "RLIMIT_NOFILE");
#ifdef RLIMIT_MEMLOCK
set_one_rlimit(&conf->rlimit_memlock, RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK");
#endif
+ set_one_rlimit(&conf->rlimit_as, RLIMIT_AS, "RLIMIT_AS");
+#ifdef RLIMIT_LOCKS
+ set_one_rlimit(&conf->rlimit_locks, RLIMIT_LOCKS, "RLIMIT_LOCKS");
+#endif
+#ifdef RLIMIT_SIGPENDING
+ set_one_rlimit(&conf->rlimit_sigpending, RLIMIT_SIGPENDING, "RLIMIT_SIGPENDING");
+#endif
+#ifdef RLIMIT_MSGQUEUE
+ set_one_rlimit(&conf->rlimit_msgqueue, RLIMIT_MSGQUEUE, "RLIMIT_MSGQUEUE");
+#endif
+#ifdef RLIMIT_NICE
+ set_one_rlimit(&conf->rlimit_nice, RLIMIT_NICE, "RLIMIT_NICE");
+#endif
+#ifdef RLIMIT_RTPRIO
+ set_one_rlimit(&conf->rlimit_rtprio, RLIMIT_RTPRIO, "RLIMIT_RTPRIO");
+#endif
+#ifdef RLIMIT_RTTIME
+ set_one_rlimit(&conf->rlimit_rttime, RLIMIT_RTTIME, "RLIMIT_RTTIME");
+#endif
}
#endif
@@ -317,16 +331,21 @@ int main(int argc, char *argv[]) {
pa_mainloop *mainloop = NULL;
char *s;
int r = 0, retval = 1, d = 0;
- int daemon_pipe[2] = { -1, -1 };
- int suid_root, real_root;
- int valid_pid_file = 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 };
+#endif
#ifdef OS_IS_WIN32
- pa_time_event *timer;
- struct timeval tv;
+ pa_time_event *win32_timer;
+ struct timeval win32_tv;
#endif
-
+ char *lf = NULL;
+ int autospawn_lock_fd = -1;
#if defined(__linux__) && defined(__OPTIMIZE__)
/*
@@ -336,11 +355,14 @@ int main(int argc, char *argv[]) {
*/
if (!getenv("LD_BIND_NOW")) {
- putenv(pa_xstrdup("LD_BIND_NOW=1"));
+ char *rp;
/* We have to execute ourselves, because the libc caches the
* value of $LD_BIND_NOW on initialization. */
- pa_assert_se(execv("/proc/self/exe", argv) == 0);
+
+ pa_set_env("LD_BIND_NOW", "1");
+ pa_assert_se(rp = pa_readlink("/proc/self/exe"));
+ pa_assert_se(execv(rp, argv) == 0);
}
#endif
@@ -348,11 +370,11 @@ int main(int argc, char *argv[]) {
real_root = getuid() == 0;
suid_root = !real_root && geteuid() == 0;
#else
- real_root = 0;
- suid_root = 0;
+ real_root = FALSE;
+ suid_root = FALSE;
#endif
- if (suid_root) {
+ if (!real_root) {
/* Drop all capabilities except CAP_SYS_NICE */
pa_limit_caps();
@@ -368,29 +390,24 @@ int main(int argc, char *argv[]) {
* is just too risky tun let PA run as root all the time. */
}
- setlocale(LC_ALL, "");
+ if ((e = getenv("PULSE_PASSED_FD"))) {
+ passed_fd = atoi(e);
- if (suid_root && (pa_own_uid_in_group(PA_REALTIME_GROUP, &gid) <= 0)) {
- pa_log_info("Warning: Called SUID root, but not in group '"PA_REALTIME_GROUP"'. "
- "For enabling real-time scheduling please become a member of '"PA_REALTIME_GROUP"' , or increase the RLIMIT_RTPRIO user limit.");
- pa_drop_caps();
- pa_drop_root();
- suid_root = real_root = 0;
+ if (passed_fd <= 2)
+ passed_fd = -1;
}
- LTDL_SET_PRELOADED_SYMBOLS();
+ pa_close_all(passed_fd, -1);
- pa_ltdl_init();
+ pa_reset_sigs(-1);
+ pa_unblock_sigs(-1);
-#ifdef OS_IS_WIN32
- {
- WSADATA data;
- WSAStartup(MAKEWORD(2, 0), &data);
- }
-#endif
-
- pa_random_seed();
+ /* 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. */
+ setlocale(LC_ALL, "");
+ pa_log_set_maximal_level(PA_LOG_INFO);
pa_log_set_ident("pulseaudio");
conf = pa_daemon_conf_new();
@@ -402,24 +419,140 @@ int main(int argc, char *argv[]) {
goto finish;
if (pa_cmdline_parse(conf, argc, argv, &d) < 0) {
- pa_log("failed to parse command line.");
+ pa_log("Failed to parse command line.");
goto finish;
}
pa_log_set_maximal_level(conf->log_level);
pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL);
- if (conf->high_priority && conf->cmd == PA_CMD_DAEMON)
- pa_raise_priority();
+ pa_log_debug("Started as real root: %s, suid root: %s", pa_yes_no(real_root), pa_yes_no(suid_root));
- if (suid_root && (conf->cmd != PA_CMD_DAEMON || !conf->high_priority)) {
- pa_drop_caps();
- pa_drop_root();
+ if (!real_root && pa_have_caps()) {
+ 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 '"PA_REALTIME_GROUP"', allowing high-priority scheduling.");
+ 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 '"PA_REALTIME_GROUP"', allowing real-time scheduling.");
+ 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();
+
+ if (conf->high_priority || conf->realtime_scheduling)
+ pa_log_notice("Called SUID root and real-time/high-priority scheduling was requested in the configuration. However, we lack the necessary priviliges:\n"
+ "We are not in group '"PA_REALTIME_GROUP"' and PolicyKit refuse to grant us priviliges. Dropping SUID again.\n"
+ "For enabling real-time scheduling please acquire the appropriate PolicyKit priviliges, or become a member of '"PA_REALTIME_GROUP"', or increase the RLIMIT_NICE/RLIMIT_RTPRIO resource limits for this user.");
+ }
}
+#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 */
+
+ set_all_rlimits(conf);
+#endif
+
+ if (conf->high_priority && !pa_can_high_priority())
+ pa_log_warn("High-priority scheduling enabled in configuration but not allowed by policy.");
+
+ if (conf->high_priority && (conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START))
+ pa_raise_priority(conf->nice_level);
+
+ if (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_warn("Real-time scheduling enabled in configuration but not allowed by policy.");
+
+ 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;
+
if (conf->dl_search_path)
lt_dlsetsearchpath(conf->dl_search_path);
+#ifdef OS_IS_WIN32
+ {
+ WSADATA data;
+ WSAStartup(MAKEWORD(2, 0), &data);
+ }
+#endif
+
+ pa_random_seed();
+
switch (conf->cmd) {
case PA_CMD_DUMP_MODULES:
pa_dump_modules(conf, argc-d, argv+d);
@@ -457,10 +590,10 @@ int main(int argc, char *argv[]) {
case PA_CMD_CHECK: {
pid_t pid;
- if (pa_pid_file_check_running(&pid) < 0) {
- pa_log_info("daemon not running");
- } else {
- pa_log_info("daemon running as PID %u", pid);
+ if (pa_pid_file_check_running(&pid, "pulseaudio") < 0)
+ pa_log_info("Daemon not running");
+ else {
+ pa_log_info("Daemon running as PID %u", pid);
retval = 0;
}
@@ -469,8 +602,8 @@ int main(int argc, char *argv[]) {
}
case PA_CMD_KILL:
- if (pa_pid_file_kill(SIGINT, NULL) < 0)
- pa_log("failed to kill daemon.");
+ if (pa_pid_file_kill(SIGINT, NULL, "pulseaudio") < 0)
+ pa_log("Failed to kill daemon.");
else
retval = 0;
@@ -484,28 +617,37 @@ int main(int argc, char *argv[]) {
goto finish;
default:
- pa_assert(conf->cmd == PA_CMD_DAEMON);
+ pa_assert(conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START);
}
- if (real_root && !conf->system_instance) {
+ if (real_root && !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) {
+ else if (!real_root && conf->system_instance) {
pa_log("Root priviliges required.");
goto finish;
}
+ if (conf->cmd == PA_CMD_START) {
+ /* If we shall start PA only when it is not running yet, we
+ * first take the autospawn lock to make things
+ * synchronous. */
+
+ lf = pa_runtime_path(AUTOSPAWN_LOCK);
+ autospawn_lock_fd = pa_lock_lockfile(lf);
+ }
+
if (conf->daemonize) {
pid_t child;
int tty_fd;
if (pa_stdio_acquire() < 0) {
- pa_log("failed to acquire stdio.");
+ pa_log("Failed to acquire stdio.");
goto finish;
}
#ifdef HAVE_FORK
if (pipe(daemon_pipe) < 0) {
- pa_log("failed to create pipe.");
+ pa_log("pipe failed: %s", pa_cstrerror(errno));
goto finish;
}
@@ -515,24 +657,36 @@ int main(int argc, char *argv[]) {
}
if (child != 0) {
+ ssize_t n;
/* Father */
pa_assert_se(pa_close(daemon_pipe[1]) == 0);
daemon_pipe[1] = -1;
- if (pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL) != sizeof(retval)) {
- pa_log("read() failed: %s", pa_cstrerror(errno));
+ if ((n = pa_loop_read(daemon_pipe[0], &retval, sizeof(retval), NULL)) != sizeof(retval)) {
+
+ if (n < 0)
+ pa_log("read() failed: %s", pa_cstrerror(errno));
+
retval = 1;
}
if (retval)
- pa_log("daemon startup failed.");
+ pa_log("Daemon startup failed.");
else
- pa_log_info("daemon startup successful.");
+ pa_log_info("Daemon startup successful.");
goto finish;
}
+ if (autospawn_lock_fd >= 0) {
+ /* The lock file is unlocked from the parent, so we need
+ * to close it in the child */
+
+ pa_close(autospawn_lock_fd);
+ autospawn_lock_fd = -1;
+ }
+
pa_assert_se(pa_close(daemon_pipe[0]) == 0);
daemon_pipe[0] = -1;
#endif
@@ -552,9 +706,9 @@ int main(int argc, char *argv[]) {
pa_close(1);
pa_close(2);
- open("/dev/null", O_RDONLY);
- open("/dev/null", O_WRONLY);
- open("/dev/null", O_WRONLY);
+ 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();
#endif
@@ -577,38 +731,54 @@ int main(int argc, char *argv[]) {
#endif
}
+ pa_set_env("PULSE_INTERNAL", "1");
pa_assert_se(chdir("/") == 0);
umask(0022);
- if (conf->system_instance) {
+ if (conf->system_instance)
if (change_user() < 0)
goto finish;
- } else if (create_runtime_dir() < 0)
+
+ pa_set_env("PULSE_SYSTEM", conf->system_instance ? "1" : "0");
+
+ pa_log_info("This is PulseAudio " PACKAGE_VERSION);
+ pa_log_info("Page size is %lu bytes", (unsigned long) PA_PAGE_SIZE);
+ if (!(s = pa_get_runtime_dir()))
goto finish;
+ pa_log_info("Using runtime directory %s.", s);
+ pa_xfree(s);
+ if (!(s = pa_get_state_dir()))
+ pa_log_info("Using state directory %s.", s);
+ pa_xfree(s);
+
+ pa_log_info("Running in system mode: %s", pa_yes_no(pa_in_system_mode()));
if (conf->use_pid_file) {
- if (pa_pid_file_create() < 0) {
+ int z;
+
+ if ((z = pa_pid_file_create("pulseaudio")) != 0) {
+
+ if (conf->cmd == PA_CMD_START && z > 0) {
+ /* If we are already running and with are run in
+ * --start mode, then let's return this as success. */
+
+ pa_log_info("z=%i rock!", z);
+
+ retval = 0;
+ goto finish;
+ }
+
pa_log("pa_pid_file_create() failed.");
-#ifdef HAVE_FORK
- if (conf->daemonize)
- pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
-#endif
goto finish;
}
- valid_pid_file = 1;
+ valid_pid_file = TRUE;
}
-#ifdef HAVE_SYS_RESOURCE_H
- set_all_rlimits(conf);
-#endif
-
#ifdef SIGPIPE
signal(SIGPIPE, SIG_IGN);
#endif
- pa_log_info("Page size is %lu bytes", (unsigned long) PA_PAGE_SIZE);
-
if (pa_rtclock_hrtimer())
pa_log_info("Fresh high-resolution timers available! Bon appetit!");
else
@@ -626,21 +796,21 @@ int main(int argc, char *argv[]) {
goto finish;
}
- c->is_system_instance = !!conf->system_instance;
- c->high_priority = !!conf->high_priority;
c->default_sample_spec = conf->default_sample_spec;
c->default_n_fragments = conf->default_n_fragments;
c->default_fragment_size_msec = conf->default_fragment_size_msec;
- c->disallow_module_loading = conf->disallow_module_loading;
c->exit_idle_time = conf->exit_idle_time;
c->module_idle_time = conf->module_idle_time;
c->scache_idle_time = conf->scache_idle_time;
c->resample_method = conf->resample_method;
+ c->realtime_priority = conf->realtime_priority;
+ c->realtime_scheduling = !!conf->realtime_scheduling;
+ c->disable_remixing = !!conf->disable_remixing;
+ c->running_as_daemon = !!conf->daemonize;
pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
pa_signal_new(SIGINT, signal_callback, c);
pa_signal_new(SIGTERM, signal_callback, c);
-
#ifdef SIGUSR1
pa_signal_new(SIGUSR1, signal_callback, c);
#endif
@@ -652,72 +822,95 @@ int main(int argc, char *argv[]) {
#endif
#ifdef OS_IS_WIN32
- pa_assert_se(timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&tv), message_cb, NULL));
+ win32_timer = pa_mainloop_get_api(mainloop)->time_new(pa_mainloop_get_api(mainloop), pa_gettimeofday(&win32_tv), message_cb, NULL);
#endif
- if (conf->daemonize)
- c->running_as_daemon = 1;
-
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->default_script_file)
- r = pa_cli_command_execute_file(c, conf->default_script_file, buf, &conf->fail);
+ 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);
+
pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
pa_xfree(s);
+ /* 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.");
-#ifdef HAVE_FORK
- if (conf->daemonize)
- pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
-#endif
- } else if (!c->modules || pa_idxset_size(c->modules) == 0) {
- pa_log("daemon startup without any loaded modules, refusing to work.");
-#ifdef HAVE_FORK
- if (conf->daemonize)
- pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
-#endif
- } else {
+ 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;
+ }
+
+ if (c->default_sink_name && !pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, TRUE) && conf->fail) {
+ pa_log_error("Default sink name (%s) does not exist in name register.", c->default_sink_name);
+ goto finish;
+ }
- retval = 0;
#ifdef HAVE_FORK
- if (conf->daemonize)
- pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
+ if (daemon_pipe[1] >= 0) {
+ int ok = 0;
+ pa_loop_write(daemon_pipe[1], &ok, sizeof(ok), NULL);
+ pa_close(daemon_pipe[1]);
+ daemon_pipe[1] = -1;
+ }
#endif
- if (c->default_sink_name &&
- pa_namereg_get(c, c->default_sink_name, PA_NAMEREG_SINK, 1) == NULL) {
- pa_log_error("%s : Fatal error. Default sink name (%s) does not exist in name register.", __FILE__, c->default_sink_name);
- retval = 1;
- } else {
- pa_log_info("Daemon startup complete.");
- if (pa_mainloop_run(mainloop, &retval) < 0)
- retval = 1;
- pa_log_info("Daemon shutdown initiated.");
- }
- }
+ pa_log_info("Daemon startup complete.");
+
+ retval = 0;
+ if (pa_mainloop_run(mainloop, &retval) < 0)
+ goto finish;
+
+ pa_log_info("Daemon shutdown initiated.");
+
+finish:
+
+ if (autospawn_lock_fd >= 0)
+ pa_unlock_lockfile(lf, autospawn_lock_fd);
+
+ if (lf)
+ pa_xfree(lf);
#ifdef OS_IS_WIN32
- pa_mainloop_get_api(mainloop)->time_free(timer);
+ if (win32_timer)
+ pa_mainloop_get_api(mainloop)->time_free(win32_timer);
#endif
- pa_core_unref(c);
+ if (c) {
+ pa_core_unref(c);
+ pa_log_info("Daemon terminated.");
+ }
if (!conf->no_cpu_limit)
pa_cpu_limit_done();
pa_signal_done();
- pa_log_info("Daemon terminated.");
+#ifdef HAVE_FORK
+ if (daemon_pipe[1] >= 0)
+ pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL);
-finish:
+ pa_close_pipe(daemon_pipe);
+#endif
if (mainloop)
pa_mainloop_free(mainloop);
@@ -728,13 +921,12 @@ finish:
if (valid_pid_file)
pa_pid_file_remove();
- pa_close_pipe(daemon_pipe);
-
#ifdef OS_IS_WIN32
WSACleanup();
#endif
- pa_ltdl_done();
+ if (ltdl_init)
+ pa_ltdl_done();
#ifdef HAVE_DBUS
dbus_shutdown();
diff --git a/src/daemon/org.pulseaudio.policy b/src/daemon/org.pulseaudio.policy
new file mode 100644
index 00000000..6cdeec68
--- /dev/null
+++ b/src/daemon/org.pulseaudio.policy
@@ -0,0 +1,50 @@
+<?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
new file mode 100644
index 00000000..256e3199
--- /dev/null
+++ b/src/daemon/polkit.c
@@ -0,0 +1,165 @@
+/***
+ 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 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 <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;
+ }
+
+ 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/polkit.h b/src/daemon/polkit.h
new file mode 100644
index 00000000..0d65ec52
--- /dev/null
+++ b/src/daemon/polkit.h
@@ -0,0 +1,27 @@
+#ifndef foopolkithfoo
+#define foopolkithfoo
+
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2007 Lennart Poettering
+
+ 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.
+***/
+
+int pa_polkit_check(const char *action);
+
+#endif