Don't refuse to start on systems using GNU stow, graft, STORE et al
authorNix <nix@esperi.org.uk>
Sat, 26 Sep 2009 19:18:00 +0000 (20:18 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 29 Sep 2009 17:32:25 +0000 (19:32 +0200)
There are multiple package management systems out there which implement
packages using symlinks. The recent (otherwise useful) check to ensure that
a re-executed pulseaudio is actually reexecuting itself unfortunately breaks
in the presence of all these packaging systems, because PA_BINARY refers
to its installed location (e.g. /usr/local/bin/pulseaudio), which is a
symlink to the binary (e.g. /usr/local/stow/pulseaudio-0.9.18/bin/pulseaudio),
because /proc/self/exe always contains the canonical path of the executable,
with all symlinks resolved.

(At least one distribution uses a symlink-based packaging system, so
will be forced to apply this locally in any case.)

The fix is simple: canonicalize PA_BINARY before equality-testing. (This
should be completely safe, because the OS does just that when PA_BINARY
is executed.)

The patch is against 0.9.18, but applies without fuzz to current master.

src/daemon/main.c

index af59ade..2e16c18 100644 (file)
@@ -416,23 +416,28 @@ int main(int argc, char *argv[]) {
 
     if (!getenv("LD_BIND_NOW")) {
         char *rp;
 
     if (!getenv("LD_BIND_NOW")) {
         char *rp;
+        char *canonical_rp;
 
         /* We have to execute ourselves, because the libc caches the
          * value of $LD_BIND_NOW on initialization. */
 
         pa_set_env("LD_BIND_NOW", "1");
 
 
         /* We have to execute ourselves, because the libc caches the
          * value of $LD_BIND_NOW on initialization. */
 
         pa_set_env("LD_BIND_NOW", "1");
 
+        canonical_rp = pa_realpath(PA_BINARY);
+
         if ((rp = pa_readlink("/proc/self/exe"))) {
 
         if ((rp = pa_readlink("/proc/self/exe"))) {
 
-            if (pa_streq(rp, PA_BINARY))
+            if (pa_streq(rp, canonical_rp))
                 pa_assert_se(execv(rp, argv) == 0);
             else
                 pa_assert_se(execv(rp, argv) == 0);
             else
-                pa_log_warn("/proc/self/exe does not point to " PA_BINARY ", cannot self execute. Are you playing games?");
+                pa_log_warn("/proc/self/exe does not point to %s, cannot self execute. Are you playing games?", canonical_rp);
 
             pa_xfree(rp);
 
         } else
             pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?");
 
             pa_xfree(rp);
 
         } else
             pa_log_warn("Couldn't read /proc/self/exe, cannot self execute. Running in a chroot()?");
+
+        pa_xfree(canonical_rp);
     }
 #endif
 
     }
 #endif