aboutsummaryrefslogblamecommitdiffstats
path: root/getexecpath.c
blob: 84bfea45a1e1e8e6d9c132443cf0c3fd90c56ed2 (plain) (tree)




























































































































                                                           
/* 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