]> code.delx.au - pulseaudio/blobdiff - src/pulsecore/core-util.c
util: /etc/machine-id should be tried first, the D-Bus only as fallback for legacy...
[pulseaudio] / src / pulsecore / core-util.c
index 738bf06592ed2b6cf3be74f3ac73bb1fc6579743..fe68965c50c0295be32fe91a68a2c93f87dae039 100644 (file)
 #include <fcntl.h>
 #include <unistd.h>
 #include <limits.h>
-#include <time.h>
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/time.h>
 #include <dirent.h>
-#include <regex.h>
+
+#ifdef HAVE_LANGINFO_H
 #include <langinfo.h>
+#endif
+
+#ifdef HAVE_UNAME
 #include <sys/utsname.h>
-#include <sys/socket.h>
+#endif
+
+#if defined(HAVE_REGEX_H)
+#include <regex.h>
+#elif defined(HAVE_PCREPOSIX_H)
+#include <pcreposix.h>
+#endif
 
 #ifdef HAVE_STRTOF_L
 #include <locale.h>
 #include <windows.h>
 #endif
 
+#ifndef ENOTSUP
+#define ENOTSUP   135
+#endif
+
 #ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
 
 #ifdef __APPLE__
 #include <xlocale.h>
+#include <mach/mach_init.h>
+#include <mach/thread_act.h>
+#include <mach/thread_policy.h>
+#include <sys/sysctl.h>
 #endif
 
 #ifdef HAVE_DBUS
 #include <pulse/utf8.h>
 
 #include <pulsecore/core-error.h>
-#include <pulsecore/winsock.h>
+#include <pulsecore/socket.h>
 #include <pulsecore/log.h>
 #include <pulsecore/macro.h>
 #include <pulsecore/thread.h>
 #include <pulsecore/strbuf.h>
 #include <pulsecore/usergroup.h>
 #include <pulsecore/strlist.h>
+#include <pulsecore/cpu-x86.h>
+#include <pulsecore/pipe.h>
 
 #include "core-util.h"
 
 #define MSG_NOSIGNAL 0
 #endif
 
+#define NEWLINE "\r\n"
+#define WHITESPACE "\n\r \t"
+
 static pa_strlist *recorded_env = NULL;
 
 #ifdef OS_IS_WIN32
 
-#define PULSE_ROOTENV "PULSE_ROOT"
+/* 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;
 
-int pa_set_root(HANDLE handle) {
-    char library_path[MAX_PATH + sizeof(PULSE_ROOTENV) + 1], *sep;
+    if (!toplevel) {
+        char library_path[MAX_PATH];
+        char *p;
 
-    strcpy(library_path, PULSE_ROOTENV "=");
-
-    /* FIXME: Needs to set errno */
+        if (!GetModuleFileName(handle, library_path, MAX_PATH))
+            return NULL;
 
-    if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
-        return 0;
+        toplevel = pa_xstrdup(library_path);
 
-    sep = strrchr(library_path, PA_PATH_SEP_CHAR);
-    if (sep)
-        *sep = '\0';
+        p = strrchr(toplevel, PA_PATH_SEP_CHAR);
+        if (p)
+            *p = '\0';
 
-    if (_putenv(library_path) < 0)
-        return 0;
+        p = strrchr(toplevel, PA_PATH_SEP_CHAR);
+        if (p && (strcmp(p + 1, "bin") == 0))
+            *p = '\0';
+    }
 
-    return 1;
+    return toplevel;
 }
 
 #endif
@@ -202,27 +226,59 @@ int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
 #ifdef OS_IS_WIN32
     r = mkdir(dir);
 #else
-    {
+{
     mode_t u;
     u = umask((~m) & 0777);
     r = mkdir(dir, m);
     umask(u);
-    }
+}
 #endif
 
     if (r < 0 && errno != EEXIST)
         return -1;
 
-#ifdef HAVE_CHOWN
-    if (uid == (uid_t)-1)
+#if defined(HAVE_FSTAT) && !defined(OS_IS_WIN32)
+{
+    int fd;
+    if ((fd = open(dir,
+#ifdef O_CLOEXEC
+                   O_CLOEXEC|
+#endif
+#ifdef O_NOCTTY
+                   O_NOCTTY|
+#endif
+#ifdef O_NOFOLLOW
+                   O_NOFOLLOW|
+#endif
+                   O_RDONLY)) < 0)
+        goto fail;
+
+    if (fstat(fd, &st) < 0) {
+        pa_assert_se(pa_close(fd) >= 0);
+        goto fail;
+    }
+
+    if (!S_ISDIR(st.st_mode)) {
+        pa_assert_se(pa_close(fd) >= 0);
+        errno = EEXIST;
+        goto fail;
+    }
+
+#ifdef HAVE_FCHOWN
+    if (uid == (uid_t) -1)
         uid = getuid();
-    if (gid == (gid_t)-1)
+    if (gid == (gid_t) -1)
         gid = getgid();
-    (void) chown(dir, uid, gid);
+    if (fchown(fd, uid, gid) < 0)
+        goto fail;
 #endif
 
-#ifdef HAVE_CHMOD
-    chmod(dir, m);
+#ifdef HAVE_FCHMOD
+    (void) fchmod(fd, m);
+#endif
+
+    pa_assert_se(pa_close(fd) >= 0);
+}
 #endif
 
 #ifdef HAVE_LSTAT
@@ -501,7 +557,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, ...) {
-    size_t  size = 100;
+    size_t size = 100;
     char *c = NULL;
 
     pa_assert(format);
@@ -531,7 +587,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) {
-    size_t  size = 100;
+    size_t size = 100;
     char *c = NULL;
 
     pa_assert(format);
@@ -577,10 +633,12 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
     return b;
 }
 
+#ifdef _POSIX_PRIORITY_SCHEDULING
 static int set_scheduler(int rtprio) {
+#ifdef HAVE_SCHED_H
     struct sched_param sp;
-    int r;
 #ifdef HAVE_DBUS
+    int r;
     DBusError error;
     DBusConnection *bus;
 
@@ -601,11 +659,12 @@ static int set_scheduler(int rtprio) {
         pa_log_debug("SCHED_RR worked.");
         return 0;
     }
+#endif  /* HAVE_SCHED_H */
 
 #ifdef HAVE_DBUS
     /* Try to talk to RealtimeKit */
 
-    if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
+    if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) {
         pa_log("Failed to connect to system bus: %s\n", error.message);
         dbus_error_free(&error);
         errno = -EIO;
@@ -618,6 +677,7 @@ static int set_scheduler(int rtprio) {
     dbus_connection_set_exit_on_disconnect(bus, FALSE);
 
     r = rtkit_make_realtime(bus, 0, rtprio);
+    dbus_connection_close(bus);
     dbus_connection_unref(bus);
 
     if (r >= 0) {
@@ -627,18 +687,51 @@ static int set_scheduler(int rtprio) {
 
     errno = -r;
 #else
-    errno = r;
+    errno = 0;
 #endif
 
     return -1;
 }
+#endif
 
 /* Make the current thread a realtime thread, and acquire the highest
  * rtprio we can get that is less or equal the specified parameter. If
  * the thread is already realtime, don't do anything. */
 int pa_make_realtime(int rtprio) {
 
-#ifdef _POSIX_PRIORITY_SCHEDULING
+#if defined(OS_IS_DARWIN)
+    struct thread_time_constraint_policy ttcpolicy;
+    uint64_t freq = 0;
+    size_t size = sizeof(freq);
+    int ret;
+
+    ret = sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0);
+    if (ret < 0) {
+        pa_log_info("Unable to read CPU frequency, acquisition of real-time scheduling failed.");
+        return -1;
+    }
+
+    pa_log_debug("sysctl for hw.cpufrequency: %llu", freq);
+
+    /* See http://developer.apple.com/library/mac/#documentation/Darwin/Conceptual/KernelProgramming/scheduler/scheduler.html */
+    ttcpolicy.period = freq / 160;
+    ttcpolicy.computation = freq / 3300;
+    ttcpolicy.constraint = freq / 2200;
+    ttcpolicy.preemptible = 1;
+
+    ret = thread_policy_set(mach_thread_self(),
+                            THREAD_TIME_CONSTRAINT_POLICY,
+                            (thread_policy_t) &ttcpolicy,
+                            THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+    if (ret) {
+        pa_log_info("Unable to set real-time thread priority (%08x).", ret);
+        return -1;
+    }
+
+    pa_log_info("Successfully acquired real-time thread priority.");
+    return 0;
+
+#elif defined(_POSIX_PRIORITY_SCHEDULING)
     int p;
 
     if (set_scheduler(rtprio) >= 0) {
@@ -647,20 +740,28 @@ int pa_make_realtime(int rtprio) {
     }
 
     for (p = rtprio-1; p >= 1; p--)
-        if (set_scheduler(p)) {
+        if (set_scheduler(p) >= 0) {
             pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
             return 0;
         }
+#elif defined(OS_IS_WIN32)
+    /* Windows only allows realtime scheduling to be set on a per process basis.
+     * Therefore, instead of making the thread realtime, just give it the highest non-realtime priority. */
+    if (SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)) {
+        pa_log_info("Successfully enabled THREAD_PRIORITY_TIME_CRITICAL scheduling for thread.");
+        return 0;
+    }
 
-    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
-    return -1;
+    pa_log_warn("SetThreadPriority() failed: 0x%08X", GetLastError());
+    errno = EPERM;
 #else
-
     errno = ENOTSUP;
-    return -1;
 #endif
+    pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
+    return -1;
 }
 
+#ifdef HAVE_SYS_RESOURCE_H
 static int set_nice(int nice_level) {
 #ifdef HAVE_DBUS
     DBusError error;
@@ -670,10 +771,12 @@ static int set_nice(int nice_level) {
     dbus_error_init(&error);
 #endif
 
+#ifdef HAVE_SYS_RESOURCE_H
     if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
         pa_log_debug("setpriority() worked.");
         return 0;
     }
+#endif
 
 #ifdef HAVE_DBUS
     /* Try to talk to RealtimeKit */
@@ -703,6 +806,7 @@ static int set_nice(int nice_level) {
 
     return -1;
 }
+#endif
 
 /* Raise the priority of the current process as much as possible that
  * is <= the specified nice level..*/
@@ -717,7 +821,7 @@ int pa_raise_priority(int nice_level) {
     }
 
     for (n = nice_level+1; n < 0; n++)
-        if (set_nice(n) > 0) {
+        if (set_nice(n) >= 0) {
             pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
             return 0;
         }
@@ -785,16 +889,18 @@ int pa_match(const char *expr, const char *v) {
 
 /* Try to parse a boolean string value.*/
 int pa_parse_boolean(const char *v) {
-    const char *expr;
     pa_assert(v);
 
-    /* First we check language independant */
+    /* First we check language independent */
     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 */
+#ifdef HAVE_LANGINFO_H
+{
+    const char *expr;
+    /* And then we check language dependent */
     if ((expr = nl_langinfo(YESEXPR)))
         if (expr[0])
             if (pa_match(expr, v) > 0)
@@ -804,6 +910,8 @@ int pa_parse_boolean(const char *v) {
         if (expr[0])
             if (pa_match(expr, v) > 0)
                 return 0;
+}
+#endif
 
     errno = EINVAL;
     return -1;
@@ -812,7 +920,7 @@ int pa_parse_boolean(const char *v) {
 /* 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
- * initiallized to NULL before the first call. */
+ * initialized to NULL before the first call. */
 char *pa_split(const char *c, const char *delimiter, const char**state) {
     const char *current = *state ? *state : c;
     size_t l;
@@ -829,9 +937,6 @@ char *pa_split(const char *c, const char *delimiter, const char**state) {
     return pa_xstrndup(current, l);
 }
 
-/* What is interpreted as whitespace? */
-#define WHITESPACE " \t\n"
-
 /* Split a string into words. Otherwise similar to pa_split(). */
 char *pa_split_spaces(const char *c, const char **state) {
     const char *current = *state ? *state : c;
@@ -875,7 +980,7 @@ const char *pa_sig2str(int sig) {
     }
 #else
 
-    switch(sig) {
+    switch (sig) {
 #ifdef SIGHUP
         case SIGHUP:    return "SIGHUP";
 #endif
@@ -986,8 +1091,7 @@ static int is_group(gid_t gid, const char *name) {
     int r = -1;
 
     errno = 0;
-    if (!(group = pa_getgrgid_malloc(gid)))
-    {
+    if (!(group = pa_getgrgid_malloc(gid))) {
         if (!errno)
             errno = ENOENT;
 
@@ -1046,15 +1150,14 @@ finish:
     return r;
 }
 
-/* Check whether the specifc user id is a member of the specified group */
+/* Check whether the specific user id is a member of the specified group */
 int pa_uid_in_group(uid_t uid, const char *name) {
     struct group *group = NULL;
     char **i;
     int r = -1;
 
     errno = 0;
-    if (!(group = pa_getgrnam_malloc(name)))
-    {
+    if (!(group = pa_getgrnam_malloc(name))) {
         if (!errno)
             errno = ENOENT;
         goto finish;
@@ -1083,14 +1186,13 @@ finish:
     return r;
 }
 
-/* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
+/* Get the GID of a given group, return (gid_t) -1 on failure. */
 gid_t pa_get_gid_of_group(const char *name) {
     gid_t ret = (gid_t) -1;
     struct group *gr = NULL;
 
     errno = 0;
-    if (!(gr = pa_getgrnam_malloc(name)))
-    {
+    if (!(gr = pa_getgrnam_malloc(name))) {
         if (!errno)
             errno = ENOENT;
         goto finish;
@@ -1120,23 +1222,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;
+    errno = ENOTSUP;
     return -1;
 
 }
 
 int pa_uid_in_group(uid_t uid, const char *name) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return -1;
 }
 
 gid_t pa_get_gid_of_group(const char *name) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return (gid_t) -1;
 }
 
 int pa_check_in_group(gid_t g) {
-    errno = ENOSUP;
+    errno = ENOTSUP;
     return -1;
 }
 
@@ -1158,18 +1260,18 @@ int pa_lock_fd(int fd, int b) {
     if (fcntl(fd, F_SETLKW, &f_lock) >= 0)
         return 0;
 
-    /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
+    /* Perhaps the file descriptor was opened for read only, than try again with a read lock. */
     if (b && errno == EBADF) {
         f_lock.l_type = F_RDLCK;
         if (fcntl(fd, F_SETLKW, &f_lock) >= 0)
             return 0;
     }
 
-    pa_log("%slock: %s", !b? "un" : "", pa_cstrerror(errno));
+    pa_log("%slock: %s", !b ? "un" : "", pa_cstrerror(errno));
 #endif
 
 #ifdef OS_IS_WIN32
-    HANDLE h = (HANDLE)_get_osfhandle(fd);
+    HANDLE h = (HANDLE) _get_osfhandle(fd);
 
     if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
         return 0;
@@ -1188,7 +1290,27 @@ int pa_lock_fd(int fd, int b) {
 char* pa_strip_nl(char *s) {
     pa_assert(s);
 
-    s[strcspn(s, "\r\n")] = 0;
+    s[strcspn(s, NEWLINE)] = 0;
+    return s;
+}
+
+char *pa_strip(char *s) {
+    char *e, *l = NULL;
+
+    /* Drops trailing whitespace. Modifies the string in
+     * place. Returns pointer to first non-space character */
+
+    s += strspn(s, WHITESPACE);
+
+    for (e = s; *e; e++)
+        if (!strchr(WHITESPACE, *e))
+            l = e;
+
+    if (l)
+        *(l+1) = 0;
+    else
+        *s = 0;
+
     return s;
 }
 
@@ -1249,7 +1371,7 @@ fail:
     return -1;
 }
 
-/* Unlock a temporary lcok file */
+/* Unlock a temporary lock file */
 int pa_unlock_lockfile(const char *fn, int fd) {
     int r = 0;
     pa_assert(fd >= 0);
@@ -1289,11 +1411,13 @@ static char *get_pulse_home(void) {
         goto finish;
     }
 
+#ifdef HAVE_GETUID
     if (st.st_uid != getuid()) {
         pa_log_error("Home directory %s not ours.", h);
         errno = EACCES;
         goto finish;
     }
+#endif
 
     ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
 
@@ -1316,7 +1440,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, 0700U, (uid_t) -1, (gid_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;
@@ -1391,7 +1515,11 @@ static char* make_random_dir(mode_t m) {
             fn[i] = table[rand() % (sizeof(table)-1)];
 
         u = umask((~m) & 0777);
+#ifndef OS_IS_WIN32
         r = mkdir(fn, m);
+#else
+        r = mkdir(fn);
+#endif
 
         saved_errno = errno;
         umask(u);
@@ -1414,6 +1542,7 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
     if (!(p = make_random_dir(m)))
         return -1;
 
+#ifdef HAVE_SYMLINK
     if (symlink(p, k) < 0) {
         int saved_errno = errno;
 
@@ -1426,6 +1555,10 @@ static int make_random_dir_and_link(mode_t m, const char *k) {
         errno = saved_errno;
         return -1;
     }
+#else
+    pa_xfree(p);
+    return -1;
+#endif
 
     pa_xfree(p);
     return 0;
@@ -1433,11 +1566,10 @@ 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,
+     * to be kept across reboots and is usually private to the user,
      * except in system mode, where it might be accessible by other
      * users, too. Since we need POSIX locking and UNIX sockets in
      * this directory, we link it to a random subdir in /tmp, if it
@@ -1447,7 +1579,7 @@ char *pa_get_runtime_dir(void) {
 
     if ((d = getenv("PULSE_RUNTIME_PATH"))) {
 
-        if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_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;
         }
@@ -1458,7 +1590,7 @@ 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)  {
+    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));
         pa_xfree(d);
         goto fail;
@@ -1474,8 +1606,7 @@ char *pa_get_runtime_dir(void) {
     pa_xfree(mid);
 
     for (;;) {
-        /* OK, first let's check if the "runtime" symlink is already
-         * existant */
+        /* OK, first let's check if the "runtime" symlink already exists */
 
         if (!(p = pa_readlink(k))) {
 
@@ -1484,6 +1615,7 @@ char *pa_get_runtime_dir(void) {
                 goto fail;
             }
 
+#ifdef HAVE_SYMLINK
             /* Hmm, so the runtime directory didn't exist yet, so let's
              * create one in /tmp and symlink that to it */
 
@@ -1496,6 +1628,11 @@ char *pa_get_runtime_dir(void) {
 
                 goto fail;
             }
+#else
+            /* No symlink possible, so let's just create the runtime directly */
+            if (!mkdir(k))
+                goto fail;
+#endif
 
             return k;
         }
@@ -1507,9 +1644,10 @@ char *pa_get_runtime_dir(void) {
             goto fail;
         }
 
-        /* Hmm, so this symlink is still around, make sure nobody fools
-         * us */
-
+        /* Hmm, so this symlink is still around, make sure nobody fools us */
+#ifdef HAVE_LSTAT
+{
+        struct stat st;
         if (lstat(p, &st) < 0) {
 
             if (errno != ENOENT) {
@@ -1529,6 +1667,8 @@ char *pa_get_runtime_dir(void) {
 
             pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
         }
+}
+#endif
 
         pa_xfree(p);
         p = NULL;
@@ -1550,7 +1690,7 @@ char *pa_get_runtime_dir(void) {
             pa_xfree(t);
             t = NULL;
 
-            /* Hmm, someone lese was quicker then us. Let's give
+            /* Hmm, someone else was quicker then us. Let's give
              * him some time to finish, and retry. */
             pa_msleep(10);
             continue;
@@ -1583,23 +1723,9 @@ fail:
  * stored there.*/
 FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
     const char *fn;
-#ifdef OS_IS_WIN32
-    char buf[PATH_MAX];
-
-    if (!getenv(PULSE_ROOTENV))
-        pa_set_root(NULL);
-#endif
+    FILE *f;
 
     if (env && (fn = getenv(env))) {
-        FILE *f;
-
-#ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
-            /* FIXME: Needs to set errno! */
-            return NULL;
-        fn = buf;
-#endif
-
         if ((f = pa_fopen_cloexec(fn, "r"))) {
             if (result)
                 *result = pa_xstrdup(fn);
@@ -1615,7 +1741,6 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
         const char *e;
         char *lfn;
         char *h;
-        FILE *f;
 
         if ((e = getenv("PULSE_CONFIG_PATH")))
             fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
@@ -1625,15 +1750,6 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
         } else
             return NULL;
 
-#ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
-            /* FIXME: Needs to set errno! */
-            pa_xfree(lfn);
-            return NULL;
-        }
-        fn = buf;
-#endif
-
         if ((f = pa_fopen_cloexec(fn, "r"))) {
             if (result)
                 *result = pa_xstrdup(fn);
@@ -1652,22 +1768,26 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
     }
 
     if (global) {
-        FILE *f;
+        char *gfn;
 
 #ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
-            /* FIXME: Needs to set errno! */
-            return NULL;
-        global = buf;
+        if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
+            gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s",
+                                    pa_win32_get_toplevel(NULL),
+                                    global + strlen(PA_DEFAULT_CONFIG_DIR));
+        else
 #endif
+        gfn = pa_xstrdup(global);
 
-        if ((f = pa_fopen_cloexec(global, "r"))) {
-
+        if ((f = pa_fopen_cloexec(gfn, "r"))) {
             if (result)
-                *result = pa_xstrdup(global);
+                *result = gfn;
+            else
+                pa_xfree(gfn);
 
             return f;
         }
+        pa_xfree(gfn);
     }
 
     errno = ENOENT;
@@ -1676,22 +1796,8 @@ FILE *pa_open_config_file(const char *global, const char *local, const char *env
 
 char *pa_find_config_file(const char *global, const char *local, const char *env) {
     const char *fn;
-#ifdef OS_IS_WIN32
-    char buf[PATH_MAX];
-
-    if (!getenv(PULSE_ROOTENV))
-        pa_set_root(NULL);
-#endif
 
     if (env && (fn = getenv(env))) {
-
-#ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
-            /* FIXME: Needs to set errno! */
-            return NULL;
-        fn = buf;
-#endif
-
         if (access(fn, R_OK) == 0)
             return pa_xstrdup(fn);
 
@@ -1712,15 +1818,6 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
         } else
             return NULL;
 
-#ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
-            /* FIXME: Needs to set errno! */
-            pa_xfree(lfn);
-            return NULL;
-        }
-        fn = buf;
-#endif
-
         if (access(fn, R_OK) == 0) {
             char *r = pa_xstrdup(fn);
             pa_xfree(lfn);
@@ -1737,15 +1834,20 @@ char *pa_find_config_file(const char *global, const char *local, const char *env
     }
 
     if (global) {
+        char *gfn;
+
 #ifdef OS_IS_WIN32
-        if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
-            /* FIXME: Needs to set errno! */
-            return NULL;
-        global = buf;
+        if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0)
+            gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s",
+                                    pa_win32_get_toplevel(NULL),
+                                    global + strlen(PA_DEFAULT_CONFIG_DIR));
+        else
 #endif
+        gfn = pa_xstrdup(global);
 
-        if (access(global, R_OK) == 0)
-            return pa_xstrdup(global);
+        if (access(gfn, R_OK) == 0)
+            return gfn;
+        pa_xfree(gfn);
     }
 
     errno = ENOENT;
@@ -1762,7 +1864,7 @@ char *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) {
     pa_assert(s);
     pa_assert(slength > 0);
 
-    while (i < dlength && j+3 <= slength) {
+    while (j+2 < slength && i < dlength) {
         s[j++] = hex[*d >> 4];
         s[j++] = hex[*d & 0xF];
 
@@ -1878,28 +1980,41 @@ static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) {
     rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
 
     if (fn) {
-        char *r;
+        char *r, *canonical_rtp;
 
-        if (pa_is_path_absolute(fn))
+        if (pa_is_path_absolute(fn)) {
+            pa_xfree(rtp);
             return pa_xstrdup(fn);
+        }
 
         if (!rtp)
             return NULL;
 
+        /* Hopefully make the path smaller to avoid 108 char limit (fdo#44680) */
+        if ((canonical_rtp = pa_realpath(rtp))) {
+            if (strlen(rtp) >= strlen(canonical_rtp))
+                pa_xfree(rtp);
+            else {
+                pa_xfree(canonical_rtp);
+                canonical_rtp = rtp;
+            }
+        } else
+            canonical_rtp = rtp;
+
         if (prependmid) {
             char *mid;
 
             if (!(mid = pa_machine_id())) {
-                pa_xfree(rtp);
+                pa_xfree(canonical_rtp);
                 return NULL;
             }
 
-            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", rtp, mid, fn);
+            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", canonical_rtp, mid, fn);
             pa_xfree(mid);
         } else
-            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
+            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", canonical_rtp, fn);
 
-        pa_xfree(rtp);
+        pa_xfree(canonical_rtp);
         return r;
     } else
         return rtp;
@@ -1915,20 +2030,13 @@ char *pa_state_path(const char *fn, pa_bool_t appendmid) {
 
 /* Convert the string s to a signed integer in *ret_i */
 int pa_atoi(const char *s, int32_t *ret_i) {
-    char *x = NULL;
     long l;
 
     pa_assert(s);
     pa_assert(ret_i);
 
-    errno = 0;
-    l = strtol(s, &x, 0);
-
-    if (!x || *x || errno) {
-        if (!errno)
-            errno = EINVAL;
+    if (pa_atol(s, &l) < 0)
         return -1;
-    }
 
     if ((int32_t) l != l) {
         errno = ERANGE;
@@ -1967,6 +2075,28 @@ int pa_atou(const char *s, uint32_t *ret_u) {
     return 0;
 }
 
+/* Convert the string s to a signed long integer in *ret_l. */
+int pa_atol(const char *s, long *ret_l) {
+    char *x = NULL;
+    long l;
+
+    pa_assert(s);
+    pa_assert(ret_l);
+
+    errno = 0;
+    l = strtol(s, &x, 0);
+
+    if (!x || *x || errno) {
+        if (!errno)
+            errno = EINVAL;
+        return -1;
+    }
+
+    *ret_l = l;
+
+    return 0;
+}
+
 #ifdef HAVE_STRTOF_L
 static locale_t c_locale = NULL;
 
@@ -2090,7 +2220,7 @@ void *pa_will_need(const void *p, size_t l) {
 #endif
     const void *a;
     size_t size;
-    int r;
+    int r = ENOTSUP;
     size_t bs;
 
     pa_assert(p);
@@ -2168,6 +2298,7 @@ void pa_close_pipe(int fds[2]) {
 }
 
 char *pa_readlink(const char *p) {
+#ifdef HAVE_READLINK
     size_t l = 100;
 
     for (;;) {
@@ -2189,6 +2320,9 @@ char *pa_readlink(const char *p) {
         pa_xfree(c);
         l *= 2;
     }
+#else
+    return NULL;
+#endif
 }
 
 int pa_close_all(int except_fd, ...) {
@@ -2227,6 +2361,7 @@ int pa_close_all(int except_fd, ...) {
 }
 
 int pa_close_allv(const int except_fds[]) {
+#ifndef OS_IS_WIN32
     struct rlimit rl;
     int maxfd, fd;
 
@@ -2316,6 +2451,7 @@ int pa_close_allv(const int except_fds[]) {
         if (pa_close(fd) < 0 && errno != EBADF)
             return -1;
     }
+#endif  /* !OS_IS_WIN32 */
 
     return 0;
 }
@@ -2356,6 +2492,7 @@ int pa_unblock_sigs(int except, ...) {
 }
 
 int pa_unblock_sigsv(const int except[]) {
+#ifndef OS_IS_WIN32
     int i;
     sigset_t ss;
 
@@ -2367,6 +2504,9 @@ int pa_unblock_sigsv(const int except[]) {
             return -1;
 
     return sigprocmask(SIG_SETMASK, &ss, NULL);
+#else
+    return 0;
+#endif
 }
 
 int pa_reset_sigs(int except, ...) {
@@ -2405,6 +2545,7 @@ int pa_reset_sigs(int except, ...) {
 }
 
 int pa_reset_sigsv(const int except[]) {
+#ifndef OS_IS_WIN32
     int sig;
 
     for (sig = 1; sig < NSIG; sig++) {
@@ -2441,6 +2582,7 @@ int pa_reset_sigsv(const int except[]) {
                     return -1;
         }
     }
+#endif
 
     return 0;
 }
@@ -2451,7 +2593,11 @@ void pa_set_env(const char *key, const char *value) {
 
     /* This is not thread-safe */
 
-    putenv(pa_sprintf_malloc("%s=%s", key, value));
+#ifdef OS_IS_WIN32
+    SetEnvironmentVariable(key, value);
+#else
+    setenv(key, value, 1);
+#endif
 }
 
 void pa_set_env_and_record(const char *key, const char *value) {
@@ -2476,7 +2622,11 @@ void pa_unset_env_recorded(void) {
         if (!s)
             break;
 
+#ifdef OS_IS_WIN32
+        SetEnvironmentVariable(s, NULL);
+#else
         unsetenv(s);
+#endif
         pa_xfree(s);
     }
 }
@@ -2490,6 +2640,26 @@ pa_bool_t pa_in_system_mode(void) {
     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) {
+    char *s;
+    const char *state = NULL;
+
+    if (!haystack || !needle)
+        return FALSE;
+
+    while ((s = pa_split_spaces(haystack, &state))) {
+        if (pa_streq(needle, s)) {
+            pa_xfree(s);
+            return TRUE;
+        }
+
+        pa_xfree(s);
+    }
+
+    return FALSE;
+}
+
 char *pa_get_user_name_malloc(void) {
     ssize_t k;
     char *u;
@@ -2556,11 +2726,12 @@ char *pa_machine_id(void) {
     /* 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. */
+    /* First we try the /etc/machine-id, 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 = pa_fopen_cloexec(PA_MACHINE_ID, "r"))) {
+    if ((f = pa_fopen_cloexec(PA_MACHINE_ID, "r")) ||
+        (f = pa_fopen_cloexec(PA_MACHINE_ID_FALLBACK, "r"))) {
         char ln[34] = "", *r;
 
         r = fgets(ln, sizeof(ln)-1, f);
@@ -2575,26 +2746,42 @@ char *pa_machine_id(void) {
     if ((h = pa_get_host_name_malloc()))
         return h;
 
+#ifndef OS_IS_WIN32
     /* If no hostname was set we use the POSIX hostid. It's usually
      * the IPv4 address.  Might not be that stable. */
     return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
+#else
+    return NULL;
+#endif
 }
 
 char *pa_session_id(void) {
     const char *e;
 
-    if (!(e = getenv("XDG_SESSION_COOKIE")))
+    e = getenv("XDG_SESSION_ID");
+    if (!e)
         return NULL;
 
     return pa_utf8_filter(e);
 }
 
 char *pa_uname_string(void) {
+#ifdef HAVE_UNAME
     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);
+#endif
+#ifdef OS_IS_WIN32
+    OSVERSIONINFO i;
+
+    pa_zero(i);
+    i.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    pa_assert_se(GetVersionEx(&i));
+
+    return pa_sprintf_malloc("Windows %d.%d (%d) %s", i.dwMajorVersion, i.dwMinorVersion, i.dwBuildNumber, i.szCSDVersion);
+#endif
 }
 
 #ifdef HAVE_VALGRIND_MEMCHECK_H
@@ -2720,7 +2907,7 @@ char *pa_realpath(const char *path) {
     char *t;
     pa_assert(path);
 
-    /* We want only abolsute paths */
+    /* We want only absolute paths */
     if (path[0] != '/') {
         errno = EINVAL;
         return NULL;
@@ -2743,10 +2930,17 @@ char *pa_realpath(const char *path) {
         char *path_buf;
         path_buf = pa_xmalloc(PATH_MAX);
 
+#if defined(OS_IS_WIN32)
+        if (!(t = _fullpath(path_buf, path, _MAX_PATH))) {
+            pa_xfree(path_buf);
+            return NULL;
+        }
+#else
         if (!(t = realpath(path, path_buf))) {
             pa_xfree(path_buf);
             return NULL;
         }
+#endif
     }
 #else
 #error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here."
@@ -2852,9 +3046,6 @@ pa_bool_t pa_run_from_build_tree(void) {
     char *rp;
     pa_bool_t b = FALSE;
 
-    /* We abuse __OPTIMIZE__ as a check whether we are a debug build
-     * or not. */
-
     if ((rp = pa_readlink("/proc/self/exe"))) {
         b = pa_startswith(rp, PA_BUILDDIR);
         pa_xfree(rp);
@@ -2944,6 +3135,7 @@ int pa_pipe_cloexec(int pipefd[2]) {
 
     if (errno != EINVAL && errno != ENOSYS)
         return r;
+
 #endif
 
     if ((r = pipe(pipefd)) < 0)
@@ -2965,6 +3157,7 @@ int pa_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
 
     if (errno != EINVAL && errno != ENOSYS)
         return fd;
+
 #endif
 
     if ((fd = accept(sockfd, addr, addrlen)) < 0)
@@ -2999,3 +3192,109 @@ finish:
     pa_make_fd_cloexec(fileno(f));
     return f;
 }
+
+void pa_nullify_stdfds(void) {
+
+#ifndef OS_IS_WIN32
+        pa_close(STDIN_FILENO);
+        pa_close(STDOUT_FILENO);
+        pa_close(STDERR_FILENO);
+
+        pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO);
+        pa_assert_se(open("/dev/null", O_WRONLY) == STDOUT_FILENO);
+        pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO);
+#else
+        FreeConsole();
+#endif
+
+}
+
+char *pa_read_line_from_file(const char *fn) {
+    FILE *f;
+    char ln[256] = "", *r;
+
+    if (!(f = pa_fopen_cloexec(fn, "r")))
+        return NULL;
+
+    r = fgets(ln, sizeof(ln)-1, f);
+    fclose(f);
+
+    if (!r) {
+        errno = EIO;
+        return NULL;
+    }
+
+    pa_strip_nl(ln);
+    return pa_xstrdup(ln);
+}
+
+pa_bool_t pa_running_in_vm(void) {
+
+#if defined(__i386__) || defined(__x86_64__)
+
+    /* Both CPUID and DMI are x86 specific interfaces... */
+
+    uint32_t eax = 0x40000000;
+    union {
+        uint32_t sig32[3];
+        char text[13];
+    } sig;
+
+#ifdef __linux__
+    const char *const dmi_vendors[] = {
+        "/sys/class/dmi/id/sys_vendor",
+        "/sys/class/dmi/id/board_vendor",
+        "/sys/class/dmi/id/bios_vendor"
+    };
+
+    unsigned i;
+
+    for (i = 0; i < PA_ELEMENTSOF(dmi_vendors); i++) {
+        char *s;
+
+        if ((s = pa_read_line_from_file(dmi_vendors[i]))) {
+
+            if (pa_startswith(s, "QEMU") ||
+                /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+                pa_startswith(s, "VMware") ||
+                pa_startswith(s, "VMW") ||
+                pa_startswith(s, "Microsoft Corporation") ||
+                pa_startswith(s, "innotek GmbH") ||
+                pa_startswith(s, "Xen")) {
+
+                pa_xfree(s);
+                return TRUE;
+            }
+
+            pa_xfree(s);
+        }
+    }
+
+#endif
+
+    /* http://lwn.net/Articles/301888/ */
+    pa_zero(sig);
+
+    __asm__ __volatile__ (
+        /* ebx/rbx is being used for PIC! */
+        "  push %%"PA_REG_b"         \n\t"
+        "  cpuid                     \n\t"
+        "  mov %%ebx, %1             \n\t"
+        "  pop %%"PA_REG_b"          \n\t"
+
+        : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+        : "0" (eax)
+    );
+
+    if (pa_streq(sig.text, "XenVMMXenVMM") ||
+        pa_streq(sig.text, "KVMKVMKVM") ||
+        /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
+        pa_streq(sig.text, "VMwareVMware") ||
+        /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
+        pa_streq(sig.text, "Microsoft Hv"))
+        return TRUE;
+
+#endif
+
+    return FALSE;
+}