1
2 /*******************************************************************/
3 /* slibtool: a skinny libtool implementation, written in C */
4 /* Copyright (C) 2016--2020 Z. Gilboa */
5 /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
6 /*******************************************************************/
7
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <limits.h>
11 #include <errno.h>
12 #include <sys/stat.h>
13 #include <slibtool/slibtool.h>
14
15 #include "slibtool_driver_impl.h"
16 #include "slibtool_readlink_impl.h"
17
18 #ifdef __unix__
19 #include <sys/syscall.h>
20 #endif
21
22 #ifdef _MIDIPIX_ABI
23 #include <sys/fs.h>
24 #endif
25
26 #ifndef ENOTSUP
27 #define ENOTSUP EOPNOTSUPP
28 #endif
29
30 #ifdef SYS___realpathat
31 extern long syscall(int, ...);
32 #endif
33
slbt_realpath(int fdat,const char * path,int options,char * buf,size_t buflen)34 int slbt_realpath(
35 int fdat,
36 const char * path,
37 int options,
38 char * buf,
39 size_t buflen)
40 {
41 int ret;
42 int fd;
43 int fdproc;
44 struct stat st;
45 struct stat stproc;
46 char procfspath[36];
47
48 /* common validation */
49 if (!buf || (options & O_CREAT)) {
50 errno = EINVAL;
51 return -1;
52 }
53
54 /* framework-based wrapper */
55 #ifdef _MIDIPIX_ABI
56 return __fs_rpath(fdat,path,options,buf,buflen);
57 #endif
58
59 #ifdef SYS___realpathat
60 return syscall(SYS___realpathat,fdat,path,buf,buflen,0);
61 #endif
62
63 /* buflen */
64 if (buflen < PATH_MAX) {
65 errno = ENOBUFS;
66 return -1;
67 }
68
69 /* AT_FDCWD */
70 if (fdat == AT_FDCWD) {
71 return realpath(path,buf) ? 0 : -1;
72 }
73
74 /* /proc/self/fd */
75 if ((fd = openat(fdat,path,options,0)) < 0)
76 return -1;
77
78 sprintf(procfspath,"/proc/self/fd/%d",fd);
79
80 if (slbt_readlinkat(fdat,procfspath,buf,buflen)) {
81 close(fd);
82 return -1;
83 }
84
85 if ((fdproc = openat(AT_FDCWD,buf,options|O_NOFOLLOW,0)) < 0) {
86 close(fd);
87 errno = ELOOP;
88 return -1;
89 }
90
91 ret = fstat(fd,&st) || fstat(fdproc,&stproc);
92
93 close(fd);
94 close(fdproc);
95
96 if (ret || (st.st_dev != stproc.st_dev) || (st.st_ino != stproc.st_ino)) {
97 errno = ENOTSUP;
98 return -1;
99 }
100
101 return 0;
102 }
103