summaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/slibtool_lconf_impl.c5
-rw-r--r--src/internal/slibtool_realpath_impl.c103
-rw-r--r--src/internal/slibtool_realpath_impl.h13
3 files changed, 119 insertions, 2 deletions
diff --git a/src/internal/slibtool_lconf_impl.c b/src/internal/slibtool_lconf_impl.c
index 82904d2..298cb12 100644
--- a/src/internal/slibtool_lconf_impl.c
+++ b/src/internal/slibtool_lconf_impl.c
@@ -18,6 +18,7 @@
#include "slibtool_errinfo_impl.h"
#include "slibtool_symlink_impl.h"
#include "slibtool_readlink_impl.h"
+#include "slibtool_realpath_impl.h"
#include "slibtool_visibility_impl.h"
enum slbt_lconf_opt {
@@ -387,7 +388,7 @@ static int slbt_lconf_trace_result_plain(
fderr = slbt_driver_fderr(dctx);
- cpath = !(slbt_util_real_path(fdat,lconf,0,path,sizeof(path)))
+ cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path)))
? path : lconf;
switch (err) {
@@ -435,7 +436,7 @@ static int slbt_lconf_trace_result_annotated(
fderr = slbt_driver_fderr(dctx);
- cpath = !(slbt_util_real_path(fdat,lconf,0,path,sizeof(path)))
+ cpath = !(slbt_realpath(fdat,lconf,0,path,sizeof(path)))
? path : lconf;
switch (err) {
diff --git a/src/internal/slibtool_realpath_impl.c b/src/internal/slibtool_realpath_impl.c
new file mode 100644
index 0000000..e1e47b5
--- /dev/null
+++ b/src/internal/slibtool_realpath_impl.c
@@ -0,0 +1,103 @@
+/*******************************************************************/
+/* slibtool: a skinny libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <slibtool/slibtool.h>
+
+#include "slibtool_driver_impl.h"
+#include "slibtool_readlink_impl.h"
+#include "slibtool_realpath_impl.h"
+#include "slibtool_visibility_impl.h"
+
+#ifdef HAVE_SYS_SYSCALL_H
+#include <sys/syscall.h>
+#endif
+
+#ifdef _MIDIPIX_ABI
+#include <sys/fs.h>
+#endif
+
+#ifndef ENOTSUP
+#define ENOTSUP EOPNOTSUPP
+#endif
+
+#ifdef SYS___realpathat
+extern long syscall(int, ...);
+#endif
+
+slbt_hidden int slbt_realpath(
+ int fdat,
+ const char * path,
+ int options,
+ char * buf,
+ size_t buflen)
+{
+ int ret;
+ int fd;
+ int fdproc;
+ struct stat st;
+ struct stat stproc;
+ char procfspath[36];
+
+ /* common validation */
+ if (!buf || (options & O_CREAT)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* framework-based wrapper */
+#ifdef _MIDIPIX_ABI
+ return __fs_rpath(fdat,path,options,buf,buflen);
+#endif
+
+#ifdef SYS___realpathat
+ return syscall(SYS___realpathat,fdat,path,buf,buflen,0);
+#endif
+
+ /* buflen */
+ if (buflen < PATH_MAX) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ /* AT_FDCWD */
+ if (fdat == AT_FDCWD) {
+ return realpath(path,buf) ? 0 : -1;
+ }
+
+ /* /proc/self/fd */
+ if ((fd = openat(fdat,path,options,0)) < 0)
+ return -1;
+
+ sprintf(procfspath,"/proc/self/fd/%d",fd);
+
+ if (slbt_readlinkat(fdat,procfspath,buf,buflen)) {
+ close(fd);
+ return -1;
+ }
+
+ if ((fdproc = openat(AT_FDCWD,buf,options|O_NOFOLLOW,0)) < 0) {
+ close(fd);
+ errno = ELOOP;
+ return -1;
+ }
+
+ ret = fstat(fd,&st) || fstat(fdproc,&stproc);
+
+ close(fd);
+ close(fdproc);
+
+ if (ret || (st.st_dev != stproc.st_dev) || (st.st_ino != stproc.st_ino)) {
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/src/internal/slibtool_realpath_impl.h b/src/internal/slibtool_realpath_impl.h
new file mode 100644
index 0000000..01df1c1
--- /dev/null
+++ b/src/internal/slibtool_realpath_impl.h
@@ -0,0 +1,13 @@
+#ifndef SLIBTOOL_REALPATH_IMPL_H
+#define SLIBTOOL_REALPATH_IMPL_H
+
+#include <stdlib.h>
+
+int slbt_realpath(
+ int fdat,
+ const char * path,
+ int options,
+ char * buf,
+ size_t buflen);
+
+#endif