filesystem: Better OpenBSD support for SDL_GetBasePath(). Fixes #3752.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
diff --git a/src/filesystem/unix/SDL_sysfilesystem.c b/src/filesystem/unix/SDL_sysfilesystem.c
index bafd602..fa5beb8 100644
--- a/src/filesystem/unix/SDL_sysfilesystem.c
+++ b/src/filesystem/unix/SDL_sysfilesystem.c
@@ -78,6 +78,60 @@ readSymLink(const char *path)
}
#endif
+
+#if defined(__OPENBSD__)
+static char *search_path_for_binary(const char *bin)
+{
+ char *envr = getenv("PATH");
+ size_t alloc_size;
+ char *exe = NULL;
+ char *start = envr;
+ char *ptr;
+
+ if (!envr) {
+ SDL_SetError("No $PATH set");
+ return NULL;
+ }
+
+ envr = SDL_strdup(envr);
+ if (!envr) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ SDL_assert(bin != NULL);
+
+ alloc_size = SDL_strlen(bin) + SDL_strlen(envr) + 2;
+ exe = (char *) SDL_malloc(alloc_size);
+
+ do {
+ ptr = SDL_strchr(start, ':'); /* find next $PATH separator. */
+ if (ptr != start) {
+ if (ptr) {
+ *ptr = '\0';
+ }
+
+ /* build full binary path... */
+ SDL_snprintf(exe, alloc_size, "%s%s%s", start, (ptr && (ptr[-1] == '/')) ? "" : "/", bin);
+
+ if (access(exe, X_OK) == 0) { /* Exists as executable? We're done. */
+ SDL_free(envr);
+ return exe;
+ }
+ }
+ start = ptr + 1; /* start points to beginning of next element. */
+ } while (ptr != NULL);
+
+ SDL_free(envr);
+ SDL_free(exe);
+
+ SDL_SetError("Process not found in $PATH");
+ return NULL; /* doesn't exist in path. */
+}
+#endif
+
+
+
char *
SDL_GetBasePath(void)
{
@@ -96,21 +150,47 @@ SDL_GetBasePath(void)
}
#endif
#if defined(__OPENBSD__)
- char **retvalargs;
+ /* Please note that this will fail if the process was launched with a relative path and the cwd has changed, or argv is altered. So don't do that. Or add a new sysctl to OpenBSD. */
+ char **cmdline;
size_t len;
const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };
if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) {
- retvalargs = SDL_malloc(len);
- if (!retvalargs) {
+ char *exe;
+ char *realpathbuf = (char *) SDL_malloc(PATH_MAX + 1);
+ if (!realpathbuf) {
SDL_OutOfMemory();
return NULL;
}
- sysctl(mib, 4, retvalargs, &len, NULL, 0);
- retval = SDL_malloc(PATH_MAX + 1);
- if (retval)
- realpath(retvalargs[0], retval);
- SDL_free(retvalargs);
+ cmdline = SDL_malloc(len);
+ if (!cmdline) {
+ SDL_free(realpathbuf);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ sysctl(mib, 4, cmdline, &len, NULL, 0);
+
+ exe = cmdline[0];
+ if (SDL_strchr(exe, '/') == NULL) { /* not a relative or absolute path, check $PATH for it */
+ exe = search_path_for_binary(cmdline[0]);
+ }
+
+ if (exe) {
+ if (realpath(exe, realpathbuf) != NULL) {
+ retval = realpathbuf;
+ }
+
+ if (exe != cmdline[0]) {
+ SDL_free(exe);
+ }
+ }
+
+ if (!retval) {
+ SDL_free(realpathbuf);
+ }
+
+ SDL_free(cmdline);
}
#endif
#if defined(__SOLARIS__)