i3-nagbar: take our terminal execution kludge to the next level
Please read commit 2bf80528bd
first.
Then read the comment within the code of this commit.
Then run in circles and cry loudly.
fixes #1002
fixes #1026
This commit is contained in:
76
libi3/get_exe_path.c
Normal file
76
libi3/get_exe_path.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libi3.h"
|
||||
|
||||
/*
|
||||
* This function returns the absolute path to the executable it is running in.
|
||||
*
|
||||
* The implementation follows http://stackoverflow.com/a/933996/712014
|
||||
*
|
||||
*/
|
||||
const char *get_exe_path(const char *argv0) {
|
||||
static char destpath[PATH_MAX];
|
||||
char tmp[PATH_MAX];
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
/* Linux and Debian/kFreeBSD provide /proc/self/exe */
|
||||
#if defined(__linux__) || defined(__FreeBSD_kernel__)
|
||||
const char *exepath = "/proc/self/exe";
|
||||
#elif defined(__FreeBSD__)
|
||||
const char *exepath = "/proc/curproc/file";
|
||||
#endif
|
||||
ssize_t linksize;
|
||||
|
||||
if ((linksize = readlink(exepath, destpath, sizeof(destpath))) != -1) {
|
||||
/* readlink() does not NULL-terminate strings, so we have to. */
|
||||
destpath[linksize] = '\0';
|
||||
|
||||
return destpath;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* argv[0] is most likely a full path if it starts with a slash. */
|
||||
if (argv0[0] == '/')
|
||||
return 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;
|
||||
}
|
||||
|
||||
/* Fall back to searching $PATH (or _CS_PATH in absence of $PATH). */
|
||||
char *path = getenv("PATH");
|
||||
size_t pathlen;
|
||||
if (path == NULL) {
|
||||
/* _CS_PATH is typically something like "/bin:/usr/bin" */
|
||||
pathlen = confstr(_CS_PATH, tmp, sizeof(tmp));
|
||||
sasprintf(&path, ":%s", tmp);
|
||||
} else {
|
||||
pathlen = strlen(path);
|
||||
path = strdup(path);
|
||||
}
|
||||
const char *component;
|
||||
char *str = path;
|
||||
while (1) {
|
||||
if ((component = strtok(str, ":")) == NULL)
|
||||
break;
|
||||
str = NULL;
|
||||
snprintf(destpath, sizeof(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);
|
||||
return destpath;
|
||||
}
|
||||
}
|
||||
free(path);
|
||||
|
||||
/* Last resort: maybe it’s in /usr/bin? */
|
||||
return "/usr/bin/i3bar";
|
||||
}
|
Reference in New Issue
Block a user