From 8b367c7f2d77bb5e1d7586853669df644a2b1d52 Mon Sep 17 00:00:00 2001
From: Mattias Andrée <maandree@kth.se>
Date: Mon, 1 Jul 2024 21:04:33 +0200
Subject: Add getexecpath functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Mattias Andrée <maandree@kth.se>
---
 getexecpath.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)
 create mode 100644 getexecpath.c

(limited to 'getexecpath.c')

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
-- 
cgit v1.2.3-70-g09d2