1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker * Author: Aleksa Sarai <[email protected]>
4*053f45beSAndroid Build Coastguard Worker * Copyright (C) 2018-2019 SUSE LLC.
5*053f45beSAndroid Build Coastguard Worker */
6*053f45beSAndroid Build Coastguard Worker
7*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
8*053f45beSAndroid Build Coastguard Worker #include <errno.h>
9*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
10*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
11*053f45beSAndroid Build Coastguard Worker #include <string.h>
12*053f45beSAndroid Build Coastguard Worker #include <syscall.h>
13*053f45beSAndroid Build Coastguard Worker #include <limits.h>
14*053f45beSAndroid Build Coastguard Worker
15*053f45beSAndroid Build Coastguard Worker #include "helpers.h"
16*053f45beSAndroid Build Coastguard Worker
needs_openat2(const struct open_how * how)17*053f45beSAndroid Build Coastguard Worker bool needs_openat2(const struct open_how *how)
18*053f45beSAndroid Build Coastguard Worker {
19*053f45beSAndroid Build Coastguard Worker return how->resolve != 0;
20*053f45beSAndroid Build Coastguard Worker }
21*053f45beSAndroid Build Coastguard Worker
raw_openat2(int dfd,const char * path,void * how,size_t size)22*053f45beSAndroid Build Coastguard Worker int raw_openat2(int dfd, const char *path, void *how, size_t size)
23*053f45beSAndroid Build Coastguard Worker {
24*053f45beSAndroid Build Coastguard Worker int ret = syscall(__NR_openat2, dfd, path, how, size);
25*053f45beSAndroid Build Coastguard Worker return ret >= 0 ? ret : -errno;
26*053f45beSAndroid Build Coastguard Worker }
27*053f45beSAndroid Build Coastguard Worker
sys_openat2(int dfd,const char * path,struct open_how * how)28*053f45beSAndroid Build Coastguard Worker int sys_openat2(int dfd, const char *path, struct open_how *how)
29*053f45beSAndroid Build Coastguard Worker {
30*053f45beSAndroid Build Coastguard Worker return raw_openat2(dfd, path, how, sizeof(*how));
31*053f45beSAndroid Build Coastguard Worker }
32*053f45beSAndroid Build Coastguard Worker
sys_openat(int dfd,const char * path,struct open_how * how)33*053f45beSAndroid Build Coastguard Worker int sys_openat(int dfd, const char *path, struct open_how *how)
34*053f45beSAndroid Build Coastguard Worker {
35*053f45beSAndroid Build Coastguard Worker int ret = openat(dfd, path, how->flags, how->mode);
36*053f45beSAndroid Build Coastguard Worker return ret >= 0 ? ret : -errno;
37*053f45beSAndroid Build Coastguard Worker }
38*053f45beSAndroid Build Coastguard Worker
sys_renameat2(int olddirfd,const char * oldpath,int newdirfd,const char * newpath,unsigned int flags)39*053f45beSAndroid Build Coastguard Worker int sys_renameat2(int olddirfd, const char *oldpath,
40*053f45beSAndroid Build Coastguard Worker int newdirfd, const char *newpath, unsigned int flags)
41*053f45beSAndroid Build Coastguard Worker {
42*053f45beSAndroid Build Coastguard Worker int ret = syscall(__NR_renameat2, olddirfd, oldpath,
43*053f45beSAndroid Build Coastguard Worker newdirfd, newpath, flags);
44*053f45beSAndroid Build Coastguard Worker return ret >= 0 ? ret : -errno;
45*053f45beSAndroid Build Coastguard Worker }
46*053f45beSAndroid Build Coastguard Worker
touchat(int dfd,const char * path)47*053f45beSAndroid Build Coastguard Worker int touchat(int dfd, const char *path)
48*053f45beSAndroid Build Coastguard Worker {
49*053f45beSAndroid Build Coastguard Worker int fd = openat(dfd, path, O_CREAT, 0700);
50*053f45beSAndroid Build Coastguard Worker if (fd >= 0)
51*053f45beSAndroid Build Coastguard Worker close(fd);
52*053f45beSAndroid Build Coastguard Worker return fd;
53*053f45beSAndroid Build Coastguard Worker }
54*053f45beSAndroid Build Coastguard Worker
fdreadlink(int fd)55*053f45beSAndroid Build Coastguard Worker char *fdreadlink(int fd)
56*053f45beSAndroid Build Coastguard Worker {
57*053f45beSAndroid Build Coastguard Worker char *target, *tmp;
58*053f45beSAndroid Build Coastguard Worker
59*053f45beSAndroid Build Coastguard Worker E_asprintf(&tmp, "/proc/self/fd/%d", fd);
60*053f45beSAndroid Build Coastguard Worker
61*053f45beSAndroid Build Coastguard Worker target = malloc(PATH_MAX);
62*053f45beSAndroid Build Coastguard Worker if (!target)
63*053f45beSAndroid Build Coastguard Worker ksft_exit_fail_msg("fdreadlink: malloc failed\n");
64*053f45beSAndroid Build Coastguard Worker memset(target, 0, PATH_MAX);
65*053f45beSAndroid Build Coastguard Worker
66*053f45beSAndroid Build Coastguard Worker E_readlink(tmp, target, PATH_MAX);
67*053f45beSAndroid Build Coastguard Worker free(tmp);
68*053f45beSAndroid Build Coastguard Worker return target;
69*053f45beSAndroid Build Coastguard Worker }
70*053f45beSAndroid Build Coastguard Worker
fdequal(int fd,int dfd,const char * path)71*053f45beSAndroid Build Coastguard Worker bool fdequal(int fd, int dfd, const char *path)
72*053f45beSAndroid Build Coastguard Worker {
73*053f45beSAndroid Build Coastguard Worker char *fdpath, *dfdpath, *other;
74*053f45beSAndroid Build Coastguard Worker bool cmp;
75*053f45beSAndroid Build Coastguard Worker
76*053f45beSAndroid Build Coastguard Worker fdpath = fdreadlink(fd);
77*053f45beSAndroid Build Coastguard Worker dfdpath = fdreadlink(dfd);
78*053f45beSAndroid Build Coastguard Worker
79*053f45beSAndroid Build Coastguard Worker if (!path)
80*053f45beSAndroid Build Coastguard Worker E_asprintf(&other, "%s", dfdpath);
81*053f45beSAndroid Build Coastguard Worker else if (*path == '/')
82*053f45beSAndroid Build Coastguard Worker E_asprintf(&other, "%s", path);
83*053f45beSAndroid Build Coastguard Worker else
84*053f45beSAndroid Build Coastguard Worker E_asprintf(&other, "%s/%s", dfdpath, path);
85*053f45beSAndroid Build Coastguard Worker
86*053f45beSAndroid Build Coastguard Worker cmp = !strcmp(fdpath, other);
87*053f45beSAndroid Build Coastguard Worker
88*053f45beSAndroid Build Coastguard Worker free(fdpath);
89*053f45beSAndroid Build Coastguard Worker free(dfdpath);
90*053f45beSAndroid Build Coastguard Worker free(other);
91*053f45beSAndroid Build Coastguard Worker return cmp;
92*053f45beSAndroid Build Coastguard Worker }
93*053f45beSAndroid Build Coastguard Worker
94*053f45beSAndroid Build Coastguard Worker bool openat2_supported = false;
95*053f45beSAndroid Build Coastguard Worker
init(void)96*053f45beSAndroid Build Coastguard Worker void __attribute__((constructor)) init(void)
97*053f45beSAndroid Build Coastguard Worker {
98*053f45beSAndroid Build Coastguard Worker struct open_how how = {};
99*053f45beSAndroid Build Coastguard Worker int fd;
100*053f45beSAndroid Build Coastguard Worker
101*053f45beSAndroid Build Coastguard Worker BUILD_BUG_ON(sizeof(struct open_how) != OPEN_HOW_SIZE_VER0);
102*053f45beSAndroid Build Coastguard Worker
103*053f45beSAndroid Build Coastguard Worker /* Check openat2(2) support. */
104*053f45beSAndroid Build Coastguard Worker fd = sys_openat2(AT_FDCWD, ".", &how);
105*053f45beSAndroid Build Coastguard Worker openat2_supported = (fd >= 0);
106*053f45beSAndroid Build Coastguard Worker
107*053f45beSAndroid Build Coastguard Worker if (fd >= 0)
108*053f45beSAndroid Build Coastguard Worker close(fd);
109*053f45beSAndroid Build Coastguard Worker }
110