Try to use /proc/self/exe to determine the base dir. This lets systems with a
authorRyan C. Gordon <icculus@icculus.org>
Mon, 19 Mar 2007 20:15:09 +0000
changeset 840 7f071b3b121e
parent 839 cbb9d603ca71
child 841 9daa256fd70a
Try to use /proc/self/exe to determine the base dir. This lets systems with a Linux-like /proc filesystem work with PHYSFS_init(NULL). Other cleanups in Unix basedir calculation.
platform/unix.c
--- a/platform/unix.c	Mon Mar 19 20:13:37 2007 +0000
+++ b/platform/unix.c	Mon Mar 19 20:15:09 2007 +0000
@@ -307,18 +307,45 @@
 
 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
 {
-    /* If there isn't a path on argv0, then look through the $PATH for it. */
+    const char *PROC_SELF_EXE = "/proc/self/exe";
+    char *retval = NULL;
+    char *envr = NULL;
+    struct stat stbuf;
 
-    char *retval;
-    char *envr;
+    /* fast path: default behaviour can handle this. */
+    if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
+        return(NULL);  /* higher level will parse out real path from argv0. */
 
-    if (strchr(argv0, '/') != NULL)   /* default behaviour can handle this. */
-        return(NULL);
+    /*
+     * Try to avoid using argv0 unless forced to. If there's a Linux-like
+     *  /proc filesystem, you can get the full path to the current process from
+     *  the /proc/self/exe symlink.
+     */
+    if ((lstat(PROC_SELF_EXE, &stbuf) != -1) && (S_ISLNK(stbuf.st_mode)))
+    {
+        const size_t len = stbuf.st_size;
+        char *buf = (char *) allocator.Malloc(len+1);
+        if (buf != NULL)  /* if NULL, maybe you'll get lucky later. */
+        {
+            if (readlink(PROC_SELF_EXE, buf, len) != len)
+                allocator.Free(buf);
+            else
+            {
+                buf[len] = '\0';  /* readlink doesn't null-terminate. */
+                retval = buf;  /* we're good to go. */
+            } /* else */
+        } /* if */
+    } /* if */
 
-    envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
-    BAIL_IF_MACRO(!envr, NULL, NULL);
-    retval = findBinaryInPath(argv0, envr);
-    allocator.Free(envr);
+    if ((retval == NULL) && (argv0 != NULL))
+    {
+        /* If there's no dirsep on argv0, then look through $PATH for it. */
+        envr = __PHYSFS_platformCopyEnvironmentVariable("PATH");
+        BAIL_IF_MACRO(!envr, NULL, NULL);
+        retval = findBinaryInPath(argv0, envr);
+        allocator.Free(envr);
+    } /* if */
+
     return(retval);
 } /* __PHYSFS_platformCalcBaseDir */
 
@@ -442,6 +469,7 @@
     BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
     strcpy(retval, resolved_path);
 
+/* !!! FIXME: this shouldn't be here. */
 #ifdef PHYSFS_PLATFORM_MACOSX
     stripAppleBundle(retval);
 #endif