diff options
Diffstat (limited to 'src/pulsecore/core-util.c')
-rw-r--r-- | src/pulsecore/core-util.c | 342 |
1 files changed, 262 insertions, 80 deletions
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index b2c91e45..dde34d7b 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -40,6 +40,9 @@ #include <sys/stat.h> #include <sys/time.h> #include <dirent.h> +#include <regex.h> +#include <langinfo.h> +#include <sys/utsname.h> #ifdef HAVE_STRTOF_L #include <locale.h> @@ -111,6 +114,8 @@ int pa_set_root(HANDLE handle) { strcpy(library_path, PULSE_ROOTENV "="); + /* FIXME: Needs to set errno */ + if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH)) return 0; @@ -168,7 +173,7 @@ 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) { struct stat st; - int r; + int r, saved_errno; pa_assert(dir); @@ -220,7 +225,10 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) { return 0; fail: + saved_errno = errno; rmdir(dir); + errno = saved_errno; + return -1; } @@ -230,6 +238,7 @@ char *pa_parent_dir(const char *fn) { if ((slash = (char*) pa_path_get_filename(dir)) == dir) { pa_xfree(dir); + errno = ENOENT; return NULL; } @@ -337,7 +346,7 @@ ssize_t pa_loop_read(int fd, void*data, size_t size, int *type) { ret += r; data = (uint8_t*) data + r; - size -= r; + size -= (size_t) r; } return ret; @@ -368,7 +377,7 @@ ssize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { ret += r; data = (const uint8_t*) data + r; - size -= r; + size -= (size_t) r; } return ret; @@ -390,7 +399,15 @@ int pa_close(int fd) { } #endif - return close(fd); + for (;;) { + int r; + + if ((r = close(fd)) >= 0) + return r; + + if (errno != EINTR) + return r; + } } /* Print a warning messages in case that the given signal is not @@ -437,7 +454,7 @@ void pa_check_signal_is_blocked(int sig) { /* The following function is based on an example from the GNU libc * documentation. This function is similar to GNU's asprintf(). */ char *pa_sprintf_malloc(const char *format, ...) { - int size = 100; + size_t size = 100; char *c = NULL; pa_assert(format); @@ -454,11 +471,11 @@ char *pa_sprintf_malloc(const char *format, ...) { c[size-1] = 0; - if (r > -1 && r < size) + if (r > -1 && (size_t) r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = (size_t) r+1; else /* glibc 2.0 */ size *= 2; } @@ -467,7 +484,7 @@ char *pa_sprintf_malloc(const char *format, ...) { /* Same as the previous function, but use a va_list instead of an * ellipsis */ char *pa_vsprintf_malloc(const char *format, va_list ap) { - int size = 100; + size_t size = 100; char *c = NULL; pa_assert(format); @@ -484,11 +501,11 @@ char *pa_vsprintf_malloc(const char *format, va_list ap) { c[size-1] = 0; - if (r > -1 && r < size) + if (r > -1 && (size_t) r < size) return c; if (r > -1) /* glibc 2.1 */ - size = r+1; + size = (size_t) r+1; else /* glibc 2.0 */ size *= 2; } @@ -546,6 +563,8 @@ int pa_make_realtime(int rtprio) { pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority); return 0; #else + + errno = ENOTSUP; return -1; #endif } @@ -653,6 +672,7 @@ int pa_raise_priority(int nice_level) { if (nice_level < 0) { if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) { pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError()); + errno = EPERM; return .-1; } else pa_log_info("Successfully gained high priority class."); @@ -679,15 +699,55 @@ void pa_reset_priority(void) { #endif } +static int match(const char *expr, const char *v) { + int k; + regex_t re; + int r; + + if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) { + errno = EINVAL; + return -1; + } + + if ((k = regexec(&re, v, 0, NULL, 0)) == 0) + r = 1; + else if (k == REG_NOMATCH) + r = 0; + else + r = -1; + + regfree(&re); + + if (r < 0) + errno = EINVAL; + + return r; +} + /* Try to parse a boolean string value.*/ int pa_parse_boolean(const char *v) { + const char *expr; + int r; pa_assert(v); + /* First we check language independant */ if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on")) return 1; else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off")) return 0; + /* And then we check language dependant */ + if ((expr = nl_langinfo(YESEXPR))) + if (expr[0]) + if ((r = match(expr, v)) > 0) + return 1; + + if ((expr = nl_langinfo(NOEXPR))) + if (expr[0]) + if ((r = match(expr, v)) > 0) + return 0; + + errno = EINVAL; return -1; } @@ -875,11 +935,18 @@ static int is_group(gid_t gid, const char *name) { #else n = -1; #endif - if (n < 0) n = 512; - data = pa_xmalloc(n); + if (n < 0) + n = 512; + + data = pa_xmalloc((size_t) n); + + errno = 0; + if (getgrgid_r(gid, &group, data, (size_t) n, &result) < 0 || !result) { + pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno)); + + if (!errno) + errno = ENOENT; - if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) { - pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno)); goto finish; } @@ -890,8 +957,14 @@ finish: #else /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not * support getgrgid_r. */ + + errno = 0; if ((result = getgrgid(gid)) == NULL) { pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno)); + + if (!errno) + errno = ENOENT; + goto finish; } @@ -906,27 +979,32 @@ finish: /* Check the current user is member of the specified group */ int pa_own_uid_in_group(const char *name, gid_t *gid) { GETGROUPS_T *gids, tgid; - int n = sysconf(_SC_NGROUPS_MAX); - int r = -1, i; + long n = sysconf(_SC_NGROUPS_MAX); + int r = -1, i, k; pa_assert(n > 0); - gids = pa_xmalloc(sizeof(GETGROUPS_T)*n); + gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n); - if ((n = getgroups(n, gids)) < 0) { + if ((n = getgroups((int) n, gids)) < 0) { pa_log("getgroups(): %s", pa_cstrerror(errno)); goto finish; } for (i = 0; i < n; i++) { - if (is_group(gids[i], name) > 0) { + + if ((k = is_group(gids[i], name)) < 0) + goto finish; + else if (k > 0) { *gid = gids[i]; r = 1; goto finish; } } - if (is_group(tgid = getgid(), name) > 0) { + if ((k = is_group(tgid = getgid(), name)) < 0) + goto finish; + else if (k > 0) { *gid = tgid; r = 1; goto finish; @@ -949,18 +1027,25 @@ int pa_uid_in_group(uid_t uid, const char *name) { int r = -1; g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); + g_buf = pa_xmalloc((size_t) g_n); p_n = sysconf(_SC_GETPW_R_SIZE_MAX); - p_buf = pa_xmalloc(p_n); + p_buf = pa_xmalloc((size_t) p_n); + + errno = 0; + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) { + + if (!errno) + errno = ENOENT; - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) goto finish; + } r = 0; for (i = gr->gr_mem; *i; i++) { struct passwd pwbuf, *pw; + errno = 0; if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw) continue; @@ -985,10 +1070,16 @@ gid_t pa_get_gid_of_group(const char *name) { struct group grbuf, *gr; g_n = sysconf(_SC_GETGR_R_SIZE_MAX); - g_buf = pa_xmalloc(g_n); + g_buf = pa_xmalloc((size_t) g_n); + + errno = 0; + if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) { + + if (!errno) + errno = ENOENT; - if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) goto finish; + } ret = gr->gr_gid; @@ -1014,19 +1105,23 @@ int pa_check_in_group(gid_t g) { #else /* HAVE_GRP_H */ int pa_own_uid_in_group(const char *name, gid_t *gid) { + errno = ENOSUP; return -1; } int pa_uid_in_group(uid_t uid, const char *name) { + errno = ENOSUP; return -1; } gid_t pa_get_gid_of_group(const char *name) { + errno = ENOSUP; return (gid_t) -1; } int pa_check_in_group(gid_t g) { + errno = ENOSUP; return -1; } @@ -1040,7 +1135,7 @@ int pa_lock_fd(int fd, int b) { /* Try a R/W lock first */ - flock.l_type = b ? F_WRLCK : F_UNLCK; + flock.l_type = (short) (b ? F_WRLCK : F_UNLCK); flock.l_whence = SEEK_SET; flock.l_start = 0; flock.l_len = 0; @@ -1067,6 +1162,8 @@ int pa_lock_fd(int fd, int b) { return 0; pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError()); + + /* FIXME: Needs to set errno! */ #endif return -1; @@ -1133,8 +1230,11 @@ int pa_lock_lockfile(const char *fn) { fail: - if (fd >= 0) + if (fd >= 0) { + int saved_errno = errno; pa_close(fd); + errno = saved_errno; + } return -1; } @@ -1180,6 +1280,7 @@ static char *get_pulse_home(void) { if (st.st_uid != getuid()) { pa_log_error("Home directory %s not ours.", h); + errno = EACCES; return NULL; } @@ -1199,7 +1300,7 @@ 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, 0700, (pid_t) -1, (pid_t) -1) < 0) { + 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)); pa_xfree(d); return NULL; @@ -1214,31 +1315,43 @@ static char* make_random_dir(mode_t m) { "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789"; - char fn[24] = "/tmp/pulse-"; + const char *tmpdir; + char *fn; + size_t pathlen; + + if (!(tmpdir = getenv("TMPDIR"))) + if (!(tmpdir = getenv("TMP"))) + if (!(tmpdir = getenv("TEMP"))) + tmpdir = getenv("TEMPDIR"); + + if (!tmpdir || !pa_is_path_absolute(tmpdir)) + tmpdir = "/tmp"; - fn[sizeof(fn)-1] = 0; + fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir); + pathlen = strlen(fn); for (;;) { - unsigned i; + size_t i; int r; mode_t u; int saved_errno; - for (i = 11; i < sizeof(fn)-1; i++) + for (i = pathlen - 12; i < pathlen; i++) fn[i] = table[rand() % (sizeof(table)-1)]; u = umask((~m) & 0777); r = mkdir(fn, m); + saved_errno = errno; umask(u); + errno = saved_errno; if (r >= 0) - return pa_xstrdup(fn); - - errno = saved_errno; + return fn; if (errno != EEXIST) { pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno)); + pa_xfree(fn); return NULL; } } @@ -1269,6 +1382,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) { char *pa_get_runtime_dir(void) { char *d, *k = NULL, *p = NULL, *t = NULL, *mid; struct stat st; + mode_t m; /* The runtime directory shall contain dynamic data that needs NOT * to be kept accross reboots and is usuallly private to the user, @@ -1277,12 +1391,11 @@ char *pa_get_runtime_dir(void) { * this directory, we link it to a random subdir in /tmp, if it * was not explicitly configured. */ - if ((d = getenv("PULSE_RUNTIME_PATH"))) { - mode_t m; + m = pa_in_system_mode() ? 0755U : 0700U; - m = pa_in_system_mode() ? 0755 : 0700; + if ((d = getenv("PULSE_RUNTIME_PATH"))) { - if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0) { + 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)); goto fail; } @@ -1293,6 +1406,11 @@ char *pa_get_runtime_dir(void) { if (!(d = get_pulse_home())) 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)); + goto fail; + } + if (!(mid = pa_machine_id())) { pa_xfree(d); goto fail; @@ -1332,6 +1450,7 @@ char *pa_get_runtime_dir(void) { /* Make sure that this actually makes sense */ if (!pa_is_path_absolute(p)) { pa_log_error("Path %s in link %s is not absolute.", p, k); + errno = ENOENT; goto fail; } @@ -1423,6 +1542,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; fn = buf; #endif @@ -1453,6 +1573,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) { + /* FIXME: Needs to set errno! */ pa_xfree(lfn); return NULL; } @@ -1481,6 +1602,7 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; global = buf; #endif @@ -1492,9 +1614,9 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env return f; } - } else - errno = ENOENT; + } + errno = ENOENT; return NULL; } @@ -1511,6 +1633,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; fn = buf; #endif @@ -1536,6 +1659,7 @@ char *pa_find_config_file(const char *global, const char *local, const char *env #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) { + /* FIXME: Needs to set errno! */ pa_xfree(lfn); return NULL; } @@ -1560,14 +1684,16 @@ char *pa_find_config_file(const char *global, const char *local, const char *env if (global) { #ifdef OS_IS_WIN32 if (!ExpandEnvironmentStrings(global, buf, PATH_MAX)) + /* FIXME: Needs to set errno! */ return NULL; global = buf; #endif if (access(global, R_OK) == 0) return pa_xstrdup(global); - } else - errno = ENOENT; + } + + errno = ENOENT; return NULL; } @@ -1604,6 +1730,7 @@ static int hexc(char c) { if (c >= 'a' && c <= 'f') return c - 'a' + 10; + errno = EINVAL; return -1; } @@ -1742,11 +1869,16 @@ int pa_atoi(const char *s, int32_t *ret_i) { errno = 0; l = strtol(s, &x, 0); - if (!x || *x || errno != 0) + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; return -1; + } - if ((int32_t) l != l) + if ((int32_t) l != l) { + errno = ERANGE; return -1; + } *ret_i = (int32_t) l; @@ -1764,11 +1896,16 @@ int pa_atou(const char *s, uint32_t *ret_u) { errno = 0; l = strtoul(s, &x, 0); - if (!x || *x || errno != 0) + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; return -1; + } - if ((uint32_t) l != l) + if ((uint32_t) l != l) { + errno = ERANGE; return -1; + } *ret_u = (uint32_t) l; @@ -1786,7 +1923,6 @@ static void c_locale_destroy(void) { int pa_atod(const char *s, double *ret_d) { char *x = NULL; double f; - int r = 0; pa_assert(s); pa_assert(ret_d); @@ -1812,17 +1948,20 @@ int pa_atod(const char *s, double *ret_d) { f = strtod(s, &x); } - if (!x || *x || errno != 0) - r = -1; - else - *ret_d = f; + if (!x || *x || errno) { + if (!errno) + errno = EINVAL; + return -1; + } - return r; + *ret_d = f; + + return 0; } /* Same as snprintf, but guarantees NUL-termination on every platform */ -int pa_snprintf(char *str, size_t size, const char *format, ...) { - int ret; +size_t pa_snprintf(char *str, size_t size, const char *format, ...) { + size_t ret; va_list ap; pa_assert(str); @@ -1837,7 +1976,7 @@ int pa_snprintf(char *str, size_t size, const char *format, ...) { } /* Same as vsnprintf, but guarantees NUL-termination on every platform */ -int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { +size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { int ret; pa_assert(str); @@ -1849,9 +1988,12 @@ int pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { str[size-1] = 0; if (ret < 0) - ret = strlen(str); + return strlen(str); - return PA_MIN((int) size-1, ret); + if ((size_t) ret > size-1) + return size-1; + + return (size_t) ret; } /* Truncate the specified string, but guarantee that the string @@ -1875,7 +2017,7 @@ char *pa_getcwd(void) { size_t l = 128; for (;;) { - char *p = pa_xnew(char, l); + char *p = pa_xmalloc(l); if (getcwd(p, l)) return p; @@ -1900,7 +2042,7 @@ void *pa_will_need(const void *p, size_t l) { pa_assert(l > 0); a = PA_PAGE_ALIGN_PTR(p); - size = (const uint8_t*) p + l - (const uint8_t*) a; + size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a); #ifdef HAVE_POSIX_MADVISE if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) { @@ -1921,10 +2063,11 @@ void *pa_will_need(const void *p, size_t l) { if (rlim.rlim_cur < PA_PAGE_SIZE) { pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r)); + errno = EPERM; return (void*) p; } - bs = PA_PAGE_ALIGN(rlim.rlim_cur); + bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur); #else bs = PA_PAGE_SIZE*4; #endif @@ -1976,7 +2119,7 @@ char *pa_readlink(const char *p) { char *c; ssize_t n; - c = pa_xnew(char, l); + c = pa_xmalloc(l); if ((n = readlink(p, c, l-1)) < 0) { pa_xfree(c); @@ -1995,8 +2138,8 @@ char *pa_readlink(const char *p) { int pa_close_all(int except_fd, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int r, *p; va_start(ap, except_fd); @@ -2123,8 +2266,8 @@ int pa_close_allv(const int except_fds[]) { int pa_unblock_sigs(int except, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int r, *p; va_start(ap, except); @@ -2172,8 +2315,8 @@ int pa_unblock_sigsv(const int except[]) { int pa_reset_sigs(int except, ...) { va_list ap; - int n = 0, i, r; - int *p; + unsigned n = 0, i; + int *p, r; va_start(ap, except); @@ -2208,7 +2351,7 @@ int pa_reset_sigs(int except, ...) { int pa_reset_sigsv(const int except[]) { int sig; - for (sig = 1; sig < _NSIG; sig++) { + for (sig = 1; sig < NSIG; sig++) { pa_bool_t reset = TRUE; switch (sig) { @@ -2266,36 +2409,48 @@ char *pa_machine_id(void) { FILE *f; size_t l; + /* The returned value is supposed be some kind of ascii identifier + * that is unique and stable across reboots. */ + + /* First we try the D-Bus UUID, which is the best option we have, + * since it fits perfectly our needs and is not as volatile as the + * hostname which might be set from dhcp. */ + if ((f = fopen(PA_MACHINE_ID, "r"))) { char ln[34] = "", *r; r = fgets(ln, sizeof(ln)-1, f); fclose(f); - if (r) - return pa_xstrdup(pa_strip_nl(ln)); + pa_strip_nl(ln); + + if (ln[0]) + return pa_xstrdup(ln); } - l = 100; + /* The we fall back to the host name. It supposed to be somewhat + * unique, at least in a network, but may change. */ + l = 100; for (;;) { char *c; - c = pa_xnew(char, l); + c = pa_xmalloc(l); if (!pa_get_host_name(c, l)) { - if (errno == EINVAL || errno == ENAMETOOLONG) { + if (errno != EINVAL && errno != ENAMETOOLONG) + break; + + } else if (strlen(c) < l-1) { + + if (*c == 0) { pa_xfree(c); - l *= 2; - continue; + break; } - return NULL; - } - - if (strlen(c) < l-1) return c; + } /* Hmm, the hostname is as long the space we offered the * function, we cannot know if it fully fit in, so let's play @@ -2304,4 +2459,31 @@ char *pa_machine_id(void) { pa_xfree(c); l *= 2; } + + /* If no hostname was set we use the POSIX hostid. It's usually + * the IPv4 address. Mit not be that stable. */ + return pa_sprintf_malloc("%08lx", (unsigned long) gethostid); +} + +char *pa_uname_string(void) { + struct utsname u; + + pa_assert_se(uname(&u) == 0); + + return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version); } + +#ifdef HAVE_VALGRIND_MEMCHECK_H +pa_bool_t pa_in_valgrind(void) { + static int b = 0; + + /* To make heisenbugs a bit simpler to find we check for $VALGRIND + * here instead of really checking whether we run in valgrind or + * not. */ + + if (b < 1) + b = getenv("VALGRIND") ? 2 : 1; + + return b > 1; +} +#endif |