X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libi3%2Fget_exe_path.c;h=032ea3dacf60ac799b9c683d25fef892c6b75561;hb=617afc67a25c9bb7bf91a7659319e07fbe32d758;hp=fca7ba02cf5a5f3fa2787c55062b89b76ab4c0d5;hpb=6241419c86602a999a4766c24edb7b884395e433;p=i3%2Fi3 diff --git a/libi3/get_exe_path.c b/libi3/get_exe_path.c index fca7ba02..032ea3da 100644 --- a/libi3/get_exe_path.c +++ b/libi3/get_exe_path.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "libi3.h" @@ -11,10 +12,14 @@ * * The implementation follows http://stackoverflow.com/a/933996/712014 * + * Returned value must be freed by the caller. */ -const char *get_exe_path(const char *argv0) { - static char destpath[PATH_MAX]; - char tmp[PATH_MAX]; +char *get_exe_path(const char *argv0) { + size_t destpath_size = 1024; + size_t tmp_size = 1024; + char *destpath = smalloc(destpath_size); + char *tmp = smalloc(tmp_size); + #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) /* Linux and Debian/kFreeBSD provide /proc/self/exe */ @@ -25,30 +30,48 @@ const char *get_exe_path(const char *argv0) { #endif ssize_t linksize; - if ((linksize = readlink(exepath, destpath, sizeof(destpath) - 1)) != -1) { + while ((linksize = readlink(exepath, destpath, destpath_size)) == (ssize_t)destpath_size) { + destpath_size = destpath_size * 2; + destpath = srealloc(destpath, destpath_size); + } + if (linksize != -1) { /* readlink() does not NULL-terminate strings, so we have to. */ destpath[linksize] = '\0'; - + free(tmp); return destpath; } #endif /* argv[0] is most likely a full path if it starts with a slash. */ - if (argv0[0] == '/') - return argv0; + if (argv0[0] == '/') { + free(tmp); + free(destpath); + return sstrdup(argv0); + } /* if argv[0] contains a /, prepend the working directory */ - if (strchr(argv0, '/') != NULL && - getcwd(tmp, sizeof(tmp)) != NULL) { - snprintf(destpath, sizeof(destpath), "%s/%s", tmp, argv0); - return destpath; + if (strchr(argv0, '/') != NULL) { + char *retgcwd; + while ((retgcwd = getcwd(tmp, tmp_size)) == NULL && errno == ERANGE) { + tmp_size = tmp_size * 2; + tmp = srealloc(tmp, tmp_size); + } + if (retgcwd != NULL) { + free(destpath); + sasprintf(&destpath, "%s/%s", tmp, argv0); + free(tmp); + return destpath; + } } /* Fall back to searching $PATH (or _CS_PATH in absence of $PATH). */ char *path = getenv("PATH"); if (path == NULL) { /* _CS_PATH is typically something like "/bin:/usr/bin" */ - confstr(_CS_PATH, tmp, sizeof(tmp)); + while (confstr(_CS_PATH, tmp, tmp_size) > tmp_size) { + tmp_size = tmp_size * 2; + tmp = srealloc(tmp, tmp_size); + } sasprintf(&path, ":%s", tmp); } else { path = strdup(path); @@ -59,16 +82,20 @@ const char *get_exe_path(const char *argv0) { if ((component = strtok(str, ":")) == NULL) break; str = NULL; - snprintf(destpath, sizeof(destpath), "%s/%s", component, argv0); + free(destpath); + sasprintf(&destpath, "%s/%s", component, argv0); /* Of course this is not 100% equivalent to actually exec()ing the * binary, but meh. */ if (access(destpath, X_OK) == 0) { free(path); + free(tmp); return destpath; } } + free(destpath); free(path); + free(tmp); /* Last resort: maybe it’s in /usr/bin? */ - return "/usr/bin/i3-nagbar"; + return sstrdup("/usr/bin/i3-nagbar"); }