|
|
@@ -182,12 +182,42 @@ static char *findBinaryInPath(const char *bin, char *envr)
|
|
|
} /* findBinaryInPath */
|
|
|
|
|
|
|
|
|
+static char *readSymLink(const char *path)
|
|
|
+{
|
|
|
+ ssize_t len = 64;
|
|
|
+ ssize_t rc = -1;
|
|
|
+ char *retval = NULL;
|
|
|
+
|
|
|
+ while (1)
|
|
|
+ {
|
|
|
+ char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
|
|
|
+ if (ptr == NULL)
|
|
|
+ break; /* out of memory. */
|
|
|
+ retval = ptr;
|
|
|
+
|
|
|
+ rc = readlink(path, retval, len);
|
|
|
+ if (rc == -1)
|
|
|
+ break; /* not a symlink, i/o error, etc. */
|
|
|
+
|
|
|
+ else if (rc < len)
|
|
|
+ {
|
|
|
+ retval[rc] = '\0'; /* readlink doesn't null-terminate. */
|
|
|
+ return retval; /* we're good to go. */
|
|
|
+ } /* else if */
|
|
|
+
|
|
|
+ len *= 2; /* grow buffer, try again. */
|
|
|
+ } /* while */
|
|
|
+
|
|
|
+ if (retval != NULL)
|
|
|
+ allocator.Free(retval);
|
|
|
+ return NULL;
|
|
|
+} /* readSymLink */
|
|
|
+
|
|
|
+
|
|
|
char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|
|
{
|
|
|
- const char *PROC_SELF_EXE = "/proc/self/exe";
|
|
|
char *retval = NULL;
|
|
|
char *envr = NULL;
|
|
|
- struct stat stbuf;
|
|
|
|
|
|
/* fast path: default behaviour can handle this. */
|
|
|
if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
|
|
|
@@ -198,20 +228,22 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|
|
* /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)))
|
|
|
+ retval = readSymLink("/proc/self/exe");
|
|
|
+ if (retval == NULL)
|
|
|
{
|
|
|
- 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 */
|
|
|
+ /* older kernels don't have /proc/self ... try PID version... */
|
|
|
+ const unsigned long long pid = (unsigned long long) getpid();
|
|
|
+ char path[64];
|
|
|
+ const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
|
|
|
+ if ( (rc > 0) && (rc < sizeof(path)) )
|
|
|
+ retval = readSymLink(path);
|
|
|
+ } /* if */
|
|
|
+
|
|
|
+ if (retval != NULL) /* chop off filename. */
|
|
|
+ {
|
|
|
+ char *ptr = strrchr(retval, '/');
|
|
|
+ if (ptr != NULL)
|
|
|
+ *ptr = '\0';
|
|
|
} /* if */
|
|
|
|
|
|
if ((retval == NULL) && (argv0 != NULL))
|
|
|
@@ -223,6 +255,14 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0)
|
|
|
allocator.Free(envr);
|
|
|
} /* if */
|
|
|
|
|
|
+ if (retval != NULL)
|
|
|
+ {
|
|
|
+ /* try to shrink buffer... */
|
|
|
+ char *ptr = (char *) allocator.Realloc(retval, strlen(retval) + 1);
|
|
|
+ if (ptr != NULL)
|
|
|
+ retval = ptr; /* oh well if it failed. */
|
|
|
+ } /* if */
|
|
|
+
|
|
|
return(retval);
|
|
|
} /* __PHYSFS_platformCalcBaseDir */
|
|
|
|