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
| | // SPDX-License-Identifier: EUPL-1.2+
// SPDX-FileCopyrightText: 2022 Alyssa Ross <hi@alyssa.is>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/openat2.h>
#define STRINGIZE(x) STRINGIZE2(x)
#define STRINGIZE2(x) #x
[[gnu::malloc]] [[gnu::nonnull]] char *areadlink(const char *pathname)
{
char *target = NULL;
size_t link_size, target_size = 4096;
for (;;) {
free(target);
if (!(target = malloc(target_size)))
return NULL;
if ((link_size = readlink(pathname, target, target_size)) == -1)
return NULL;
if (link_size < target_size)
break;
if (target_size > (((size_t)-1) >> 1)) {
errno = ENOMEM;
return NULL;
}
target_size <<= 1;
}
target[link_size] = '\0';
return target;
}
int main(int argc, char **argv)
{
// -1 because both paths include a null terminator.
char fdpath[sizeof "/proc/self/fd/" + sizeof(STRINGIZE(INT_MAX)) - 1];
char *target;
int rootfd, targetfd;
struct open_how how = { .flags = O_PATH };
// Ensure INT_MAX is actually defined, because otherwise
// sizeof("INT_MAX") will silently be used instead in fdpath's
// size.
(void) INT_MAX;
if (argc != 3) {
fprintf(stderr, "Usage: %s root dir\n", argc ? argv[0] : "resolve_in_root");
return 1;
}
if ((rootfd = syscall(SYS_openat2, AT_FDCWD, argv[1], &how, sizeof how)) == -1)
err(EXIT_FAILURE, "opening %s", argv[1]);
how.resolve = RESOLVE_IN_ROOT | RESOLVE_NO_MAGICLINKS | RESOLVE_NO_XDEV;
if ((targetfd = syscall(SYS_openat2, rootfd, argv[2], &how, sizeof how)) == -1)
err(EXIT_FAILURE, "opening %s with %s:/", argv[2], argv[1]);
assert(snprintf(fdpath, sizeof fdpath, "/proc/self/fd/%d", targetfd) < sizeof fdpath);
target = areadlink(fdpath);
if (!target)
err(EXIT_FAILURE, "reading %s", fdpath);
puts(target);
}
|