aboutsummaryrefslogtreecommitdiffstats
path: root/getexecpath.c
blob: 84bfea45a1e1e8e6d9c132443cf0c3fd90c56ed2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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