aboutsummaryrefslogtreecommitdiffstats
path: root/getexecpath.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2024-07-01 21:04:33 +0200
committerMattias Andrée <maandree@kth.se>2024-07-01 21:04:33 +0200
commit8b367c7f2d77bb5e1d7586853669df644a2b1d52 (patch)
tree4baf58c802d3b8c6816167c976010ff003f2f1cb /getexecpath.c
parentAdd readlink and readmagiclink functions (diff)
downloadlibsimple-8b367c7f2d77bb5e1d7586853669df644a2b1d52.tar.gz
libsimple-8b367c7f2d77bb5e1d7586853669df644a2b1d52.tar.bz2
libsimple-8b367c7f2d77bb5e1d7586853669df644a2b1d52.tar.xz
Add getexecpath functions
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'getexecpath.c')
-rw-r--r--getexecpath.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/getexecpath.c b/getexecpath.c
new file mode 100644
index 0000000..84bfea4
--- /dev/null
+++ b/getexecpath.c
@@ -0,0 +1,125 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifndef TEST
+
+#include <sys/auxv.h>
+
+
+extern char *argv0;
+
+
+static char *
+getexecpath_by_execfn(void)
+{
+ unsigned long auxval;
+ char *execpath, *path, *target;
+ const char *name, *s, *fdlink;
+ size_t n;
+
+ auxval = getauxval(AT_EXECFN);
+ if (!auxval)
+ return NULL;
+
+ name = (void *)auxval;
+ if (strstarts(name, "/dev/fd/"))
+ s = &name[sizeof("/dev/fd/") - 1U];
+ else if (strstarts(name, "/proc/self/fd/"))
+ s = &name[sizeof("/proc/self/fd/") - 1U];
+ else
+ return libsimple_abspath(name, NULL);
+
+ while (isdigit(*s))
+ s++;
+ if (*s) {
+ n = (size_t)(s - name);
+ path = malloc(n + 1U);
+ if (!path)
+ return NULL;
+ memcpy(path, name, n);
+ path[n] = '\0';
+ fdlink = path;
+ } else {
+ path = NULL;
+ fdlink = name;
+ }
+ target = libsimple_readmagiclink(fdlink);
+ free(path);
+ if (!target)
+ return NULL;
+ execpath = malloc(strlen(target) + strlen(s) + 1U);
+ if (!execpath) {
+ free(target);
+ return NULL;
+ }
+ stpcpy(stpcpy(execpath, target), s);
+ free(target);
+
+ return execpath;
+}
+
+
+static char *
+getexecpath_by_execfd(void)
+{
+ unsigned long auxval;
+ int fd;
+ char path[sizeof("/dev/fd/") + 3U * sizeof(int)];
+
+ errno = 0;
+ auxval = getauxval(AT_EXECFN);
+ if (!auxval && errno)
+ return NULL;
+ fd = (int)auxval;
+
+ sprintf(path, "/dev/fd/%i", fd);
+ return libsimple_readmagiclink(path);
+}
+
+
+static char *
+getexecpath_by_proc_exe(void)
+{
+ return libsimple_readmagiclink("/proc/self/exe");
+}
+
+
+static char *
+getexecpath_by_argv0(void)
+{
+ char *s = argv0;
+
+ if (strchr(s, '/'))
+ return libsimple_abspath(s, NULL);
+
+ return NULL;
+}
+
+
+char *
+libsimple_getexecpath(void)
+{
+ char *r;
+
+ if ((r = getexecpath_by_execfn()))
+ return r;
+ if ((r = getexecpath_by_execfd()))
+ return r;
+ if ((r = getexecpath_by_proc_exe()))
+ return r;
+ if ((r = getexecpath_by_argv0()))
+ return r;
+
+ return NULL;
+}
+
+
+#else
+#include "test.h"
+
+int
+main(void) /* TODO test */
+{
+ return 0;
+}
+
+#endif