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 |
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; |