misc/libphysfs/platform_unix.c
changeset 12218 bb5522e88ab2
parent 9799 a3fe81c3bc02
child 12897 0088bcccd19a
equal deleted inserted replaced
12217:ea891871f481 12218:bb5522e88ab2
    11 
    11 
    12 #ifdef PHYSFS_PLATFORM_UNIX
    12 #ifdef PHYSFS_PLATFORM_UNIX
    13 
    13 
    14 #include <ctype.h>
    14 #include <ctype.h>
    15 #include <unistd.h>
    15 #include <unistd.h>
       
    16 #include <stdlib.h>
    16 #include <sys/types.h>
    17 #include <sys/types.h>
    17 #include <pwd.h>
    18 #include <pwd.h>
    18 #include <sys/stat.h>
    19 #include <sys/stat.h>
    19 #include <sys/param.h>
    20 #include <sys/param.h>
    20 #include <dirent.h>
    21 #include <dirent.h>
    21 #include <time.h>
    22 #include <time.h>
    22 #include <errno.h>
    23 #include <errno.h>
       
    24 #include <limits.h>
    23 
    25 
    24 #if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H)
    26 #if PHYSFS_PLATFORM_LINUX && !defined(PHYSFS_HAVE_MNTENT_H)
    25 #define PHYSFS_HAVE_MNTENT_H 1
    27 #define PHYSFS_HAVE_MNTENT_H 1
    26 #elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H)
    28 #elif PHYSFS_PLATFORM_SOLARIS && !defined(PHYSFS_HAVE_SYS_MNTTAB_H)
    27 #define PHYSFS_HAVE_SYS_MNTTAB_H 1
    29 #define PHYSFS_HAVE_SYS_MNTTAB_H 1
   169         if (ptr)
   171         if (ptr)
   170             *ptr = '\0';
   172             *ptr = '\0';
   171 
   173 
   172         binlen = strlen(bin);
   174         binlen = strlen(bin);
   173         size = strlen(start) + binlen + 2;
   175         size = strlen(start) + binlen + 2;
   174         if (size > alloc_size)
   176         if (size >= alloc_size)
   175         {
   177         {
   176             char *x = (char *) allocator.Realloc(exe, size);
   178             char *x = (char *) allocator.Realloc(exe, size);
   177             if (!x)
   179             if (!x)
   178             {
   180             {
   179                 if (exe != NULL)
   181                 if (exe != NULL)
   191             strcat(exe, "/");
   193             strcat(exe, "/");
   192         strcat(exe, bin);
   194         strcat(exe, bin);
   193 
   195 
   194         if (access(exe, X_OK) == 0)  /* Exists as executable? We're done. */
   196         if (access(exe, X_OK) == 0)  /* Exists as executable? We're done. */
   195         {
   197         {
   196             exe[size - binlen - 1] = '\0'; /* chop off filename, leave '/' */
   198             exe[(size - binlen) - 1] = '\0'; /* chop off filename, leave '/' */
   197             return exe;
   199             return exe;
   198         } /* if */
   200         } /* if */
   199 
   201 
   200         start = ptr + 1;  /* start points to beginning of next element. */
   202         start = ptr + 1;  /* start points to beginning of next element. */
   201     } while (ptr != NULL);
   203     } while (ptr != NULL);
   242 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
   244 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
   243 {
   245 {
   244     char *retval = NULL;
   246     char *retval = NULL;
   245     const char *envr = NULL;
   247     const char *envr = NULL;
   246 
   248 
   247     /*
   249     /* Try to avoid using argv0 unless forced to. Try system-specific stuff. */
   248      * Try to avoid using argv0 unless forced to. If there's a Linux-like
   250     
   249      *  /proc filesystem, you can get the full path to the current process from
   251     #if PHYSFS_PLATFORM_FREEBSD
   250      *  the /proc/self/exe symlink.
   252     {
       
   253         char fullpath[PATH_MAX];
       
   254         size_t buflen = sizeof (fullpath);
       
   255         int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
       
   256         if (sysctl(mib, 4, fullpath, &buflen, NULL, 0) != -1)
       
   257             retval = __PHYSFS_strdup(fullpath);
       
   258     }
       
   259     #elif PHYSFS_PLATFORM_SOLARIS
       
   260     {
       
   261         const char *path = getexecname();
       
   262         if ((path != NULL) && (path[0] == '/'))  /* must be absolute path... */
       
   263             retval = __PHYSFS_strdup(path);
       
   264     }
       
   265     #endif
       
   266 
       
   267     if (retval)
       
   268         return retval;   /* already got it. */
       
   269 
       
   270     /* If there's a Linux-like /proc filesystem, you can get the full path to
       
   271      *  the current process from a symlink in there.
   251      */
   272      */
   252     retval = readSymLink("/proc/self/exe");
   273 
   253     if (retval == NULL)
   274     if (access("/proc", F_OK) == 0)
   254     {
   275     {
   255         /* older kernels don't have /proc/self ... try PID version... */
   276         retval = readSymLink("/proc/self/exe");
   256         const unsigned long long pid = (unsigned long long) getpid();
   277         if (!retval) retval = readSymLink("/proc/curproc/file");
   257         char path[64];
   278         if (!retval) retval = readSymLink("/proc/curproc/exe");
   258         const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
   279         if (retval == NULL)
   259         if ( (rc > 0) && (rc < sizeof(path)) )
   280         {
   260             retval = readSymLink(path);
   281             /* older kernels don't have /proc/self ... try PID version... */
       
   282             const unsigned long long pid = (unsigned long long) getpid();
       
   283             char path[64];
       
   284             const int rc = (int) snprintf(path,sizeof(path),"/proc/%llu/exe",pid);
       
   285             if ( (rc > 0) && (rc < sizeof(path)) )
       
   286                 retval = readSymLink(path);
       
   287         } /* if */
   261     } /* if */
   288     } /* if */
   262 
   289 
   263     if (retval != NULL)  /* chop off filename. */
   290     if (retval != NULL)  /* chop off filename. */
   264     {
   291     {
   265         char *ptr = strrchr(retval, '/');
   292         char *ptr = strrchr(retval, '/');
   270             allocator.Free(retval);
   297             allocator.Free(retval);
   271             retval = NULL;
   298             retval = NULL;
   272         } /* else */
   299         } /* else */
   273     } /* if */
   300     } /* if */
   274 
   301 
   275     /* No /proc/self/exe, but we have an argv[0] we can parse? */
   302     /* No /proc/self/exe, etc, but we have an argv[0] we can parse? */
   276     if ((retval == NULL) && (argv0 != NULL))
   303     if ((retval == NULL) && (argv0 != NULL))
   277     {
   304     {
   278         /* fast path: default behaviour can handle this. */
   305         /* fast path: default behaviour can handle this. */
   279         if (strchr(argv0, '/') != NULL)
   306         if (strchr(argv0, '/') != NULL)
   280             return NULL;  /* higher level parses out real path from argv0. */
   307             return NULL;  /* higher level parses out real path from argv0. */
   308     /*
   335     /*
   309      * We use XDG's base directory spec, even if you're not on Linux.
   336      * We use XDG's base directory spec, even if you're not on Linux.
   310      *  This isn't strictly correct, but the results are relatively sane
   337      *  This isn't strictly correct, but the results are relatively sane
   311      *  in any case.
   338      *  in any case.
   312      *
   339      *
   313      * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
   340      * https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
   314      */
   341      */
   315     const char *envr = getenv("XDG_DATA_HOME");
   342     const char *envr = getenv("XDG_DATA_HOME");
   316     const char *append = "/";
   343     const char *append = "/";
   317     char *retval = NULL;
   344     char *retval = NULL;
   318     size_t len = 0;
   345     size_t len = 0;