]> git.sur5r.net Git - i3/i3/blob - libi3/get_exe_path.c
fca7ba02cf5a5f3fa2787c55062b89b76ab4c0d5
[i3/i3] / libi3 / get_exe_path.c
1 #include <unistd.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <limits.h>
5 #include <stdlib.h>
6
7 #include "libi3.h"
8
9 /*
10  * This function returns the absolute path to the executable it is running in.
11  *
12  * The implementation follows http://stackoverflow.com/a/933996/712014
13  *
14  */
15 const char *get_exe_path(const char *argv0) {
16         static char destpath[PATH_MAX];
17         char tmp[PATH_MAX];
18
19 #if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
20         /* Linux and Debian/kFreeBSD provide /proc/self/exe */
21 #if defined(__linux__) || defined(__FreeBSD_kernel__)
22         const char *exepath = "/proc/self/exe";
23 #elif defined(__FreeBSD__)
24         const char *exepath = "/proc/curproc/file";
25 #endif
26         ssize_t linksize;
27
28         if ((linksize = readlink(exepath, destpath, sizeof(destpath) - 1)) != -1) {
29                 /* readlink() does not NULL-terminate strings, so we have to. */
30                 destpath[linksize] = '\0';
31
32                 return destpath;
33         }
34 #endif
35
36         /* argv[0] is most likely a full path if it starts with a slash. */
37         if (argv0[0] == '/')
38                 return argv0;
39
40         /* if argv[0] contains a /, prepend the working directory */
41         if (strchr(argv0, '/') != NULL &&
42                 getcwd(tmp, sizeof(tmp)) != NULL) {
43                 snprintf(destpath, sizeof(destpath), "%s/%s", tmp, argv0);
44                 return destpath;
45         }
46
47         /* Fall back to searching $PATH (or _CS_PATH in absence of $PATH). */
48         char *path = getenv("PATH");
49         if (path == NULL) {
50                 /* _CS_PATH is typically something like "/bin:/usr/bin" */
51                 confstr(_CS_PATH, tmp, sizeof(tmp));
52                 sasprintf(&path, ":%s", tmp);
53         } else {
54                 path = strdup(path);
55         }
56         const char *component;
57         char *str = path;
58         while (1) {
59                 if ((component = strtok(str, ":")) == NULL)
60                         break;
61                 str = NULL;
62                 snprintf(destpath, sizeof(destpath), "%s/%s", component, argv0);
63                 /* Of course this is not 100% equivalent to actually exec()ing the
64                  * binary, but meh. */
65                 if (access(destpath, X_OK) == 0) {
66                         free(path);
67                         return destpath;
68                 }
69         }
70         free(path);
71
72         /* Last resort: maybe it’s in /usr/bin? */
73         return "/usr/bin/i3-nagbar";
74 }