From 4046759f611e28b8b3201e7da2550813f6e099d0 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 23 Aug 2013 23:41:35 -0400 Subject: [PATCH] Better basedir detection for various Unix platforms. --- src/physfs.c | 6 ++--- src/physfs_internal.h | 5 ++++ src/physfs_platforms.h | 7 +++++- src/platform_unix.c | 53 +++++++++++++++++++++++++++++++----------- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/physfs.c b/src/physfs.c index 60615695..a1abbc88 100644 --- a/src/physfs.c +++ b/src/physfs.c @@ -1347,13 +1347,13 @@ int PHYSFS_isInit(void) } /* PHYSFS_isInit */ -static char *PHYSFS_strdup(const char *str) +char *__PHYSFS_strdup(const char *str) { char *retval = (char *) allocator.Malloc(strlen(str) + 1); if (retval) strcpy(retval, str); return retval; -} /* PHYSFS_strdup */ +} /* __PHYSFS_strdup */ /* MAKE SURE you hold stateLock before calling this! */ @@ -1400,7 +1400,7 @@ static int doRegisterArchiver(const PHYSFS_Archiver *_archiver) info = (PHYSFS_ArchiveInfo *) &archiver->info; memset(info, '\0', sizeof (*info)); /* NULL in case an alloc fails. */ #define CPYSTR(item) \ - info->item = PHYSFS_strdup(_archiver->info.item); \ + info->item = __PHYSFS_strdup(_archiver->info.item); \ GOTO_IF_MACRO(!info->item, PHYSFS_ERR_OUT_OF_MEMORY, regfailed); CPYSTR(extension); CPYSTR(description); diff --git a/src/physfs_internal.h b/src/physfs_internal.h index a954bc46..94171c94 100644 --- a/src/physfs_internal.h +++ b/src/physfs_internal.h @@ -631,6 +631,11 @@ void __PHYSFS_platformReleaseMutex(void *mutex); */ int __PHYSFS_platformSetDefaultAllocator(PHYSFS_Allocator *a); +/* + * Like strdup(), but uses the current PhysicsFS allocator. + */ +char *__PHYSFS_strdup(const char *str); + #ifdef __cplusplus } #endif diff --git a/src/physfs_platforms.h b/src/physfs_platforms.h index daf044d8..bc78e0bb 100644 --- a/src/physfs_platforms.h +++ b/src/physfs_platforms.h @@ -48,7 +48,12 @@ # define PHYSFS_PLATFORM_SOLARIS 1 # define PHYSFS_PLATFORM_UNIX 1 # define PHYSFS_PLATFORM_POSIX 1 -#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__DragonFly__) +#elif defined(__FreeBSD__) || defined(__DragonFly__) +# define PHYSFS_PLATFORM_FREEBSD 1 +# define PHYSFS_PLATFORM_BSD 1 +# define PHYSFS_PLATFORM_UNIX 1 +# define PHYSFS_PLATFORM_POSIX 1 +#elif defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) # define PHYSFS_PLATFORM_BSD 1 # define PHYSFS_PLATFORM_UNIX 1 # define PHYSFS_PLATFORM_POSIX 1 diff --git a/src/platform_unix.c b/src/platform_unix.c index cb58bdbd..e11c24bc 100644 --- a/src/platform_unix.c +++ b/src/platform_unix.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H) #define PHYSFS_HAVE_MNTENT_H 1 @@ -244,20 +246,45 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0) char *retval = NULL; const char *envr = 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. + /* Try to avoid using argv0 unless forced to. Try system-specific stuff. */ + + #if PHYSFS_PLATFORM_FREEBSD + { + char fullpath[PATH_MAX]; + size_t buflen = sizeof (fullpath); + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1) + retval = __PHYSFS_strdup(fullpath); + } + #elif PHYSFS_PLATFORM_SOLARIS + { + const char *path = getexecname(); + if ((path != NULL) && (path[0] == '/')) /* must be absolute path... */ + retval = __PHYSFS_strdup(path); + } + #endif + + if (retval) + return retval; /* already got it. */ + + /* If there's a Linux-like /proc filesystem, you can get the full path to + * the current process from a symlink in there. */ - retval = readSymLink("/proc/self/exe"); - if (retval == NULL) + + if (access("/proc", F_OK) == 0) { - /* 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); + retval = readSymLink("/proc/self/exe"); + if (!retval) retval = readSymLink("/proc/curproc/file"); + if (!retval) retval = readSymLink("/proc/curproc/exe"); + if (retval == NULL) + { + /* 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 */ if (retval != NULL) /* chop off filename. */ @@ -272,7 +299,7 @@ char *__PHYSFS_platformCalcBaseDir(const char *argv0) } /* else */ } /* if */ - /* No /proc/self/exe, but we have an argv[0] we can parse? */ + /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */ if ((retval == NULL) && (argv0 != NULL)) { /* fast path: default behaviour can handle this. */