diff options
Diffstat (limited to 'src/daemon/main.c')
-rw-r--r-- | src/daemon/main.c | 111 |
1 files changed, 88 insertions, 23 deletions
diff --git a/src/daemon/main.c b/src/daemon/main.c index 789d104b..14594416 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -1,5 +1,3 @@ -/* $Id$ */ - /*** This file is part of PulseAudio. @@ -96,6 +94,8 @@ #include "ltdl-bind-now.h" #include "polkit.h" +#define AUTOSPAWN_LOCK "autospawn.lock" + #ifdef HAVE_LIBWRAP /* Only one instance of these variables */ int allow_severity = LOG_INFO; @@ -202,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; @@ -246,7 +253,8 @@ static int change_user(void) { /* Relevant for pa_runtime_path() */ pa_set_env("PULSE_RUNTIME_PATH", PA_SYSTEM_RUNTIME_PATH); - pa_set_env("PULSE_CONFIG_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."); @@ -336,6 +344,8 @@ int main(int argc, char *argv[]) { pa_time_event *win32_timer; struct timeval win32_tv; #endif + char *lf = NULL; + int autospawn_lock_fd = -1; #if defined(__linux__) && defined(__OPTIMIZE__) /* @@ -364,7 +374,7 @@ int main(int argc, char *argv[]) { suid_root = FALSE; #endif - if (suid_root) { + if (!real_root) { /* Drop all capabilities except CAP_SYS_NICE */ pa_limit_caps(); @@ -416,20 +426,26 @@ int main(int argc, char *argv[]) { pa_log_set_maximal_level(conf->log_level); pa_log_set_target(conf->auto_log_target ? PA_LOG_STDERR : conf->log_target, NULL); - if (suid_root) { - pa_bool_t allow_realtime, allow_high_priority; + 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()) { + pa_bool_t allow_high_priority = FALSE, allow_realtime = FALSE; - /* Ok, we're suid root, so let's better not enable high prio - * or RT by default */ + /* Let's better not enable high prio or RT by default */ - allow_high_priority = allow_realtime = FALSE; + 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->high_priority || conf->realtime_scheduling) + 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 and high-priority scheduling."); - allow_realtime = conf->realtime_scheduling; - allow_high_priority = conf->high_priority; + 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) { @@ -455,7 +471,6 @@ int main(int argc, char *argv[]) { * let's give it up early */ pa_drop_caps(); - suid_root = FALSE; 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" @@ -478,13 +493,13 @@ int main(int argc, char *argv[]) { 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) + if (conf->high_priority && (conf->cmd == PA_CMD_DAEMON || conf->cmd == PA_CMD_START)) pa_raise_priority(conf->nice_level); - if (suid_root) { + if (pa_have_caps()) { pa_bool_t drop; - drop = conf->cmd != PA_CMD_DAEMON || !conf->realtime_scheduling; + drop = (conf->cmd != PA_CMD_DAEMON && conf->cmd != PA_CMD_START) || !conf->realtime_scheduling; #ifdef RLIMIT_RTPRIO if (!drop) { @@ -520,6 +535,8 @@ int main(int argc, char *argv[]) { 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; @@ -600,7 +617,7 @@ 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) @@ -610,6 +627,15 @@ int main(int argc, char *argv[]) { 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; @@ -653,6 +679,14 @@ int main(int argc, char *argv[]) { 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 @@ -705,13 +739,35 @@ int main(int argc, char *argv[]) { if (change_user() < 0) goto finish; + 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); - pa_log_info("Using runtime directory %s.", s = pa_get_runtime_dir()); + 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."); goto finish; } @@ -740,7 +796,6 @@ int main(int argc, char *argv[]) { goto finish; } - c->is_system_instance = !!conf->system_instance; 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; @@ -810,11 +865,12 @@ int main(int argc, char *argv[]) { goto finish; } - #ifdef HAVE_FORK - if (conf->daemonize) { + 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 @@ -828,6 +884,12 @@ int main(int argc, char *argv[]) { finish: + if (autospawn_lock_fd >= 0) + pa_unlock_lockfile(lf, autospawn_lock_fd); + + if (lf) + pa_xfree(lf); + #ifdef OS_IS_WIN32 if (win32_timer) pa_mainloop_get_api(mainloop)->time_free(win32_timer); @@ -844,6 +906,9 @@ finish: pa_signal_done(); #ifdef HAVE_FORK + if (daemon_pipe[1] >= 0) + pa_loop_write(daemon_pipe[1], &retval, sizeof(retval), NULL); + pa_close_pipe(daemon_pipe); #endif |