From d9f0a872080ae9e17a66fecafc2dd6768473e118 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 8 Jul 2009 17:59:29 -0400 Subject: [PATCH] Merged 1001:b0c6f2f4f361 through 1003:a28d30d275e2 from default branch. Fixes /proc/*/exe behaviour on Linux. --- platform/unix.c | 70 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/platform/unix.c b/platform/unix.c index 2b47cc99..7846166b 100644 --- a/platform/unix.c +++ b/platform/unix.c @@ -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 */