X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/59968f8e2cd90eb06c6d8b247811129cfe3980ea..d806b197144733607b0ecb8678c6ee5d99ccc9ea:/src/pulsecore/core-util.c diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index 834c69be..08932b62 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -150,6 +150,8 @@ static pa_strlist *recorded_env = NULL; #ifdef OS_IS_WIN32 +#include "poll.h" + /* Returns the directory of the current DLL, with '/bin/' removed if it is the last component */ char *pa_win32_get_toplevel(HANDLE handle) { static char *toplevel = NULL; @@ -216,11 +218,13 @@ void pa_make_fd_cloexec(int fd) { } -/** Creates a directory securely */ -int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { +/** Creates a directory securely. Will create parent directories recursively if + * required. This will not update permissions on parent directories if they + * already exist, however. */ +int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid, bool update_perms) { struct stat st; int r, saved_errno; - pa_bool_t retry = TRUE; + bool retry = true; pa_assert(dir); @@ -239,8 +243,8 @@ again: if (r < 0 && errno == ENOENT && retry) { /* If a parent directory in the path doesn't exist, try to create that * first, then try again. */ - pa_make_secure_parent_dir(dir, m, uid, gid); - retry = FALSE; + pa_make_secure_parent_dir(dir, m, uid, gid, false); + retry = false; goto again; } @@ -274,6 +278,9 @@ again: goto fail; } + if (!update_perms) + return 0; + #ifdef HAVE_FCHOWN if (uid == (uid_t) -1) uid = getuid(); @@ -335,14 +342,14 @@ char *pa_parent_dir(const char *fn) { } /* Creates a the parent directory of the specified path securely */ -int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid) { +int pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid, bool update_perms) { int ret = -1; char *dir; if (!(dir = pa_parent_dir(fn))) goto finish; - if (pa_make_secure_dir(dir, m, uid, gid) < 0) + if (pa_make_secure_dir(dir, m, uid, gid, update_perms) < 0) goto finish; ret = 0; @@ -363,13 +370,26 @@ ssize_t pa_read(int fd, void *buf, size_t count, int *type) { #ifdef OS_IS_WIN32 if (!type || *type == 0) { + int err; ssize_t r; +retry: if ((r = recv(fd, buf, count, 0)) >= 0) return r; - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); + err = WSAGetLastError(); + if (err != WSAENOTSOCK) { + /* transparently handle non-blocking sockets, by waiting + * for readiness */ + if (err == WSAEWOULDBLOCK) { + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLIN; + if (pa_poll(&pfd, 1, -1) >= 0) { + goto retry; + } + } + errno = err; return r; } @@ -395,7 +415,11 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { if (!type || *type == 0) { ssize_t r; +#ifdef OS_IS_WIN32 + int err; +retry: +#endif for (;;) { if ((r = send(fd, buf, count, MSG_NOSIGNAL)) < 0) { @@ -409,8 +433,19 @@ ssize_t pa_write(int fd, const void *buf, size_t count, int *type) { } #ifdef OS_IS_WIN32 - if (WSAGetLastError() != WSAENOTSOCK) { - errno = WSAGetLastError(); + err = WSAGetLastError(); + if (err != WSAENOTSOCK) { + /* transparently handle non-blocking sockets, by waiting + * for readiness */ + if (err == WSAEWOULDBLOCK) { + struct pollfd pfd; + pfd.fd = fd; + pfd.events = POLLOUT; + if (pa_poll(&pfd, 1, -1) >= 0) { + goto retry; + } + } + errno = err; return r; } #else @@ -649,6 +684,10 @@ static int set_scheduler(int rtprio) { struct sched_param sp; #ifdef HAVE_DBUS int r; + long long rttime; +#ifdef HAVE_SYS_RESOURCE_H + struct rlimit rl; +#endif DBusError error; DBusConnection *bus; @@ -684,18 +723,38 @@ static int set_scheduler(int rtprio) { /* We need to disable exit on disconnect because otherwise * dbus_shutdown will kill us. See * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */ - dbus_connection_set_exit_on_disconnect(bus, FALSE); + dbus_connection_set_exit_on_disconnect(bus, false); - r = rtkit_make_realtime(bus, 0, rtprio); - dbus_connection_close(bus); - dbus_connection_unref(bus); + rttime = rtkit_get_rttime_usec_max(bus); + if (rttime >= 0) { +#ifdef HAVE_SYS_RESOURCE_H + r = getrlimit(RLIMIT_RTTIME, &rl); - if (r >= 0) { - pa_log_debug("RealtimeKit worked."); - return 0; + if (r >= 0 && (long long) rl.rlim_max > rttime) { + pa_log_info("Clamping rlimit-rttime to %lld for RealtimeKit\n", rttime); + rl.rlim_cur = rl.rlim_max = rttime; + r = setrlimit(RLIMIT_RTTIME, &rl); + + if (r < 0) + pa_log("setrlimit() failed: %s", pa_cstrerror(errno)); + } +#endif + r = rtkit_make_realtime(bus, 0, rtprio); + dbus_connection_close(bus); + dbus_connection_unref(bus); + + if (r >= 0) { + pa_log_debug("RealtimeKit worked."); + return 0; + } + + errno = -r; + } else { + dbus_connection_close(bus); + dbus_connection_unref(bus); + errno = -rttime; } - errno = -r; #else errno = 0; #endif @@ -801,7 +860,7 @@ static int set_nice(int nice_level) { /* We need to disable exit on disconnect because otherwise * dbus_shutdown will kill us. See * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */ - dbus_connection_set_exit_on_disconnect(bus, FALSE); + dbus_connection_set_exit_on_disconnect(bus, false); r = rtkit_make_high_priority(bus, 0, nice_level); dbus_connection_unref(bus); @@ -902,9 +961,11 @@ int pa_parse_boolean(const char *v) { pa_assert(v); /* First we check language independent */ - if (pa_streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) + if (pa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t") + || !strcasecmp(v, "yes") || !strcasecmp(v, "true") || !strcasecmp(v, "on")) return 1; - else if (pa_streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) + else if (pa_streq(v, "0") || !strcasecmp(v, "n") || !strcasecmp(v, "f") + || !strcasecmp(v, "no") || !strcasecmp(v, "false") || !strcasecmp(v, "off")) return 0; #ifdef HAVE_LANGINFO_H @@ -927,6 +988,48 @@ int pa_parse_boolean(const char *v) { return -1; } +/* Try to parse a volume string to pa_volume_t. The allowed formats are: + * db, % and unsigned integer */ +int pa_parse_volume(const char *v, pa_volume_t *volume) { + int len, ret = -1; + uint32_t i; + double d; + char str[64]; + + pa_assert(v); + pa_assert(volume); + + len = strlen(v); + + if (len >= 64) + return -1; + + memcpy(str, v, len + 1); + + if (str[len - 1] == '%') { + str[len - 1] = '\0'; + if (pa_atou(str, &i) == 0) { + *volume = PA_CLAMP_VOLUME((uint64_t) PA_VOLUME_NORM * i / 100); + ret = 0; + } + } else if (len > 2 && (str[len - 1] == 'b' || str[len - 1] == 'B') && + (str[len - 2] == 'd' || str[len - 2] == 'D')) { + str[len - 2] = '\0'; + if (pa_atod(str, &d) == 0) { + *volume = pa_sw_volume_from_dB(d); + ret = 0; + } + } else { + if (pa_atou(v, &i) == 0) { + *volume= PA_CLAMP_VOLUME(i); + ret = 0; + } + + } + + return ret; +} + /* Split the specified string wherever one of the strings in delimiter * occurs. Each time it is called returns a newly allocated string * with pa_xmalloc(). The variable state points to, should be @@ -1502,8 +1605,8 @@ char *pa_get_state_dir(void) { /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same * dir then this will break. */ - if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0) { - pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1, true) < 0) { + pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); pa_xfree(d); return NULL; } @@ -1644,8 +1747,8 @@ char *pa_get_runtime_dir(void) { d = getenv("PULSE_RUNTIME_PATH"); if (d) { - if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { - pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) { + pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); goto fail; } @@ -1657,9 +1760,8 @@ char *pa_get_runtime_dir(void) { if (d) { k = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", d); - if (pa_make_secure_dir(k, m, (uid_t) -1, (gid_t) -1) < 0) { - free(k); - pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + if (pa_make_secure_dir(k, m, (uid_t) -1, (gid_t) -1, true) < 0) { + pa_log_error("Failed to create secure directory (%s): %s", k, pa_cstrerror(errno)); goto fail; } @@ -1671,8 +1773,8 @@ char *pa_get_runtime_dir(void) { if (!d) goto fail; - if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0) { - pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno)); + if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) { + pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); pa_xfree(d); goto fail; } @@ -1712,8 +1814,9 @@ char *pa_get_runtime_dir(void) { goto fail; } #else - /* No symlink possible, so let's just create the runtime directly */ - if (mkdir(k) < 0) + /* No symlink possible, so let's just create the runtime directly + * Do not check again if it exists since it cannot be a symlink */ + if (mkdir(k) < 0 && errno != EEXIST) goto fail; #endif @@ -2010,7 +2113,7 @@ size_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { } /* Returns nonzero when *s starts with *pfx */ -pa_bool_t pa_startswith(const char *s, const char *pfx) { +bool pa_startswith(const char *s, const char *pfx) { size_t l; pa_assert(s); @@ -2022,7 +2125,7 @@ pa_bool_t pa_startswith(const char *s, const char *pfx) { } /* Returns nonzero when *s ends with *sfx */ -pa_bool_t pa_endswith(const char *s, const char *sfx) { +bool pa_endswith(const char *s, const char *sfx) { size_t l1, l2; pa_assert(s); @@ -2034,7 +2137,7 @@ pa_bool_t pa_endswith(const char *s, const char *sfx) { return l1 >= l2 && pa_streq(s + l1 - l2, sfx); } -pa_bool_t pa_is_path_absolute(const char *fn) { +bool pa_is_path_absolute(const char *fn) { pa_assert(fn); #ifndef OS_IS_WIN32 @@ -2061,10 +2164,10 @@ char *pa_make_path_absolute(const char *p) { return r; } -/* if fn is null return the PulseAudio run time path in s (~/.pulse) - * if fn is non-null and starts with / return fn - * otherwise append fn to the run time path and return it */ -static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) { +/* If fn is NULL, return the PulseAudio runtime or state dir (depending on the + * rt parameter). If fn is non-NULL and starts with /, return fn. Otherwise, + * append fn to the runtime/state dir and return it. */ +static char *get_path(const char *fn, bool prependmid, bool rt) { char *rtp; rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir(); @@ -2111,11 +2214,11 @@ static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) { } char *pa_runtime_path(const char *fn) { - return get_path(fn, FALSE, TRUE); + return get_path(fn, false, true); } -char *pa_state_path(const char *fn, pa_bool_t appendmid) { - return get_path(fn, appendmid, FALSE); +char *pa_state_path(const char *fn, bool appendmid) { + return get_path(fn, appendmid, false); } /* Convert the string s to a signed integer in *ret_i */ @@ -2464,7 +2567,7 @@ int pa_close_allv(const int except_fds[]) { struct dirent *de; while ((de = readdir(d))) { - pa_bool_t found; + bool found; long l; char *e = NULL; int i; @@ -2494,10 +2597,10 @@ int pa_close_allv(const int except_fds[]) { if (fd == dirfd(d)) continue; - found = FALSE; + found = false; for (i = 0; except_fds[i] >= 0; i++) if (except_fds[i] == fd) { - found = TRUE; + found = true; break; } @@ -2526,12 +2629,12 @@ int pa_close_allv(const int except_fds[]) { for (fd = 3; fd < maxfd; fd++) { int i; - pa_bool_t found; + bool found; - found = FALSE; + found = false; for (i = 0; except_fds[i] >= 0; i++) if (except_fds[i] == fd) { - found = TRUE; + found = true; break; } @@ -2639,12 +2742,12 @@ int pa_reset_sigsv(const int except[]) { int sig; for (sig = 1; sig < NSIG; sig++) { - pa_bool_t reset = TRUE; + bool reset = true; switch (sig) { case SIGKILL: case SIGSTOP: - reset = FALSE; + reset = false; break; default: { @@ -2652,7 +2755,7 @@ int pa_reset_sigsv(const int except[]) { for (i = 0; except[i] > 0; i++) { if (sig == except[i]) { - reset = FALSE; + reset = false; break; } } @@ -2721,33 +2824,33 @@ void pa_unset_env_recorded(void) { } } -pa_bool_t pa_in_system_mode(void) { +bool pa_in_system_mode(void) { const char *e; if (!(e = getenv("PULSE_SYSTEM"))) - return FALSE; + return false; return !!atoi(e); } /* Checks a whitespace-separated list of words in haystack for needle */ -pa_bool_t pa_str_in_list_spaces(const char *haystack, const char *needle) { +bool pa_str_in_list_spaces(const char *haystack, const char *needle) { char *s; const char *state = NULL; if (!haystack || !needle) - return FALSE; + return false; while ((s = pa_split_spaces(haystack, &state))) { if (pa_streq(needle, s)) { pa_xfree(s); - return TRUE; + return true; } pa_xfree(s); } - return FALSE; + return false; } char *pa_get_user_name_malloc(void) { @@ -2875,7 +2978,7 @@ char *pa_uname_string(void) { } #ifdef HAVE_VALGRIND_MEMCHECK_H -pa_bool_t pa_in_valgrind(void) { +bool pa_in_valgrind(void) { static int b = 0; /* To make heisenbugs a bit simpler to find we check for $VALGRIND @@ -2976,16 +3079,16 @@ char *pa_escape(const char *p, const char *chars) { char *pa_unescape(char *p) { char *s, *d; - pa_bool_t escaped = FALSE; + bool escaped = false; for (s = p, d = p; *s; s++) { if (!escaped && *s == '\\') { - escaped = TRUE; + escaped = true; continue; } *(d++) = *s; - escaped = FALSE; + escaped = false; } *d = 0; @@ -3003,7 +3106,7 @@ char *pa_realpath(const char *path) { return NULL; } -#if defined(__GLIBC__) || defined(__APPLE__) +#if defined(__GLIBC__) { char *r; @@ -3130,22 +3233,20 @@ void pa_reset_personality(void) { } -#if defined(__linux__) && !defined(__OPTIMIZE__) - -pa_bool_t pa_run_from_build_tree(void) { +bool pa_run_from_build_tree(void) { char *rp; - pa_bool_t b = FALSE; + static bool b = false; - if ((rp = pa_readlink("/proc/self/exe"))) { - b = pa_startswith(rp, PA_BUILDDIR); - pa_xfree(rp); - } + PA_ONCE_BEGIN { + if ((rp = pa_readlink("/proc/self/exe"))) { + b = pa_startswith(rp, PA_BUILDDIR); + pa_xfree(rp); + } + } PA_ONCE_END; return b; } -#endif - const char *pa_get_temp_dir(void) { const char *t; @@ -3318,7 +3419,7 @@ char *pa_read_line_from_file(const char *fn) { return pa_xstrdup(ln); } -pa_bool_t pa_running_in_vm(void) { +bool pa_running_in_vm(void) { #if defined(__i386__) || defined(__x86_64__) @@ -3353,7 +3454,7 @@ pa_bool_t pa_running_in_vm(void) { pa_startswith(s, "Xen")) { pa_xfree(s); - return TRUE; + return true; } pa_xfree(s); @@ -3382,9 +3483,9 @@ pa_bool_t pa_running_in_vm(void) { pa_streq(sig.text, "VMwareVMware") || /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */ pa_streq(sig.text, "Microsoft Hv")) - return TRUE; + return true; #endif - return FALSE; + return false; }