[PATCH RFC] Support newer kernels lacking noat syscalls

Mark Salter msalter at redhat.com
Tue Apr 24 14:50:15 UTC 2012


Upstream Linux kernel development is requiring new architecture ports to
use only the default set of generic syscalls. This means familiar syscalls
like open have been replaced with "at" versions (openat).  C6X is one such
recent kernel port. The following patch is just a first cut, brute force
sort of patch that I have been using to get by while focusing on the kernel.
I thought I'd post it, generate some discussion and hopefully get it into
shape for upstream inclusion.
---
 ldso/include/dl-syscall.h                          |   42 +++++++++++++++++++-
 libc/stdio/popen.c                                 |    2 +-
 libc/stdlib/system.c                               |    2 +-
 libc/stdlib/unix_grantpt.c                         |    2 +-
 libc/sysdeps/linux/common/__syscall_fcntl.c        |    8 ++++
 libc/sysdeps/linux/common/access.c                 |    9 ++++
 libc/sysdeps/linux/common/chmod.c                  |   10 ++++-
 libc/sysdeps/linux/common/chown.c                  |   16 +++++++-
 libc/sysdeps/linux/common/dup2.c                   |   13 ++++++-
 libc/sysdeps/linux/common/fstatat.c                |    2 +-
 libc/sysdeps/linux/common/fstatat64.c              |    2 +-
 libc/sysdeps/linux/common/fstatfs.c                |   27 +++++++++++++
 libc/sysdeps/linux/common/ftruncate.c              |    7 +++
 libc/sysdeps/linux/common/getdents.c               |    4 +-
 libc/sysdeps/linux/common/lchown.c                 |   14 ++++++-
 libc/sysdeps/linux/common/link.c                   |   10 +++++
 libc/sysdeps/linux/common/llseek.c                 |    4 ++
 libc/sysdeps/linux/common/lstat.c                  |    3 +
 libc/sysdeps/linux/common/mkdir.c                  |    8 ++++
 libc/sysdeps/linux/common/mknod.c                  |    5 ++
 libc/sysdeps/linux/common/not-cancel.h             |    8 ++++
 libc/sysdeps/linux/common/open.c                   |   11 +++++
 libc/sysdeps/linux/common/pipe.c                   |   11 +++++-
 libc/sysdeps/linux/common/readlink.c               |    8 ++++
 libc/sysdeps/linux/common/rename.c                 |    9 ++++
 libc/sysdeps/linux/common/rmdir.c                  |    9 ++++
 libc/sysdeps/linux/common/stat.c                   |    5 ++-
 libc/sysdeps/linux/common/statfs.c                 |   28 +++++++++++++
 libc/sysdeps/linux/common/stubs.c                  |    8 +---
 libc/sysdeps/linux/common/symlink.c                |    9 ++++
 libc/sysdeps/linux/common/truncate.c               |    7 +++
 libc/sysdeps/linux/common/unlink.c                 |    9 ++++-
 libc/sysdeps/linux/common/ustat.c                  |    2 +
 libc/sysdeps/linux/common/utimes.c                 |   22 ++++++++++
 .../linuxthreads.old/sysdeps/pthread/not-cancel.h  |    8 ++++
 35 files changed, 323 insertions(+), 21 deletions(-)

diff --git a/ldso/include/dl-syscall.h b/ldso/include/dl-syscall.h
index 547dad1..ad0eea3 100644
--- a/ldso/include/dl-syscall.h
+++ b/ldso/include/dl-syscall.h
@@ -23,7 +23,7 @@ extern int _dl_errno;
 /* Pull in whatever this particular arch's kernel thinks the kernel version of
  * struct stat should look like.  It turns out that each arch has a different
  * opinion on the subject, and different kernel revs use different names... */
-#if defined(__sparc_v9__) && (__WORDSIZE == 64)
+#if !defined(__NR_stat) || (defined(__sparc_v9__) && (__WORDSIZE == 64))
 #define kernel_stat64 stat
 #else
 #define kernel_stat stat
@@ -35,6 +35,7 @@ extern int _dl_errno;
 #define	S_ISUID		04000	/* Set user ID on execution.  */
 #define	S_ISGID		02000	/* Set group ID on execution.  */
 
+#define AT_FDCWD	-100
 
 /* Here are the definitions for some syscalls that are used
    by the dynamic linker.  The idea is that we want to be able
@@ -48,9 +49,20 @@ static __always_inline _syscall1(void, _dl_exit, int, status)
 #define __NR__dl_close __NR_close
 static __always_inline _syscall1(int, _dl_close, int, fd)
 
+#if defined(__NR_open)
 #define __NR__dl_open __NR_open
 static __always_inline _syscall3(int, _dl_open, const char *, fn, int, flags,
                         __kernel_mode_t, mode)
+#elif defined(__NR_openat)
+#define __NR__dl_openat __NR_openat
+static __always_inline _syscall4(int, _dl_openat, int, dirfd, const char *, fn,
+				 int, flags, __kernel_mode_t, mode)
+static __always_inline ssize_t
+_dl_open(const char *fn, int flags, __kernel_mode_t mode)
+{
+	return _dl_openat(AT_FDCWD, fn, flags, mode);
+}
+#endif
 
 #define __NR__dl_write __NR_write
 static __always_inline _syscall3(unsigned long, _dl_write, int, fd,
@@ -64,11 +76,28 @@ static __always_inline _syscall3(unsigned long, _dl_read, int, fd,
 static __always_inline _syscall3(int, _dl_mprotect, const void *, addr,
                         unsigned long, len, int, prot)
 
+#if defined(__NR_stat)
 #define __NR__dl_stat __NR_stat
 static __always_inline _syscall2(int, _dl_stat, const char *, file_name,
                         struct stat *, buf)
+#elif defined(__NR_fstatat64)
+#define __NR__dl_fstatat64 __NR_fstatat64
+static __always_inline _syscall4(int, _dl_fstatat64, int, dirfd, const char *, fn,
+			struct stat *, stat, int, flags)
+static __always_inline int
+_dl_stat(const char *fn, struct stat *stat)
+{
+	return _dl_fstatat64(AT_FDCWD, fn, stat, 0);
+}
+#else
+#error "no stat"
+#endif
 
+#if defined(__NR_fstat)
 #define __NR__dl_fstat __NR_fstat
+#elif defined(__NR_fstat64)
+#define __NR__dl_fstat __NR_fstat64
+#endif
 static __always_inline _syscall2(int, _dl_fstat, int, fd, struct stat *, buf)
 
 #define __NR__dl_munmap __NR_munmap
@@ -104,9 +133,20 @@ static __always_inline _syscall0(gid_t, _dl_getegid)
 #define __NR__dl_getpid __NR_getpid
 static __always_inline _syscall0(gid_t, _dl_getpid)
 
+#if defined(__NR_readlink)
 #define __NR__dl_readlink __NR_readlink
 static __always_inline _syscall3(int, _dl_readlink, const char *, path, char *, buf,
                         size_t, bufsiz)
+#elif defined(__NR_readlinkat)
+#define __NR__dl_readlinkat __NR_readlinkat
+static __always_inline _syscall4(int, _dl_readlinkat, int, dirfd,
+				 const char *, fn, char *, buf, size_t, size)
+static __always_inline int
+_dl_readlink(const char *fn, char *buf, size_t size)
+{
+	return _dl_readlinkat(AT_FDCWD, fn, buf, size);
+}
+#endif
 
 #ifdef __NR_pread64
 #define __NR___syscall_pread __NR_pread64
diff --git a/libc/stdio/popen.c b/libc/stdio/popen.c
index d5c60cf..2a425bb 100644
--- a/libc/stdio/popen.c
+++ b/libc/stdio/popen.c
@@ -29,7 +29,7 @@
 
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
-#if ! defined __NR_vfork
+#if ! defined __NR_vfork && ! defined __NR_clone
 # define vfork fork
 # define VFORK_LOCK		((void) 0)
 # define VFORK_UNLOCK		((void) 0)
diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c
index a92c307..3fcbc9e 100644
--- a/libc/stdlib/system.c
+++ b/libc/stdlib/system.c
@@ -26,7 +26,7 @@ extern __typeof(system) __libc_system;
 #if !defined __UCLIBC_HAS_THREADS_NATIVE__ || defined __sparc__
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
-#ifndef __NR_vfork
+#if !defined(__NR_vfork) && !defined(__NR_clone)
 # define vfork fork
 #endif
 
diff --git a/libc/stdlib/unix_grantpt.c b/libc/stdlib/unix_grantpt.c
index 1be0a7d..1ac33dc 100644
--- a/libc/stdlib/unix_grantpt.c
+++ b/libc/stdlib/unix_grantpt.c
@@ -33,7 +33,7 @@
 
 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
 #include <sys/syscall.h>
-#if ! defined __NR_vfork
+#if ! defined __NR_vfork && !defined __NR_clone
 #define vfork fork
 #endif
 
diff --git a/libc/sysdeps/linux/common/__syscall_fcntl.c b/libc/sysdeps/linux/common/__syscall_fcntl.c
index 6d4c339..b13cdf5 100644
--- a/libc/sysdeps/linux/common/__syscall_fcntl.c
+++ b/libc/sysdeps/linux/common/__syscall_fcntl.c
@@ -38,7 +38,11 @@ int __fcntl_nocancel (int fd, int cmd, ...)
 #  endif
 	}
 # endif
+# if defined __NR_fcntl64
+	return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#else
 	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
+#endif
 }
 libc_hidden_def(__fcntl_nocancel)
 
@@ -81,8 +85,12 @@ int __libc_fcntl (int fd, int cmd, ...)
 #  endif
 	}
 # endif
+# if defined __NR_fcntl64
+	return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
+#else
 	return INLINE_SYSCALL (fcntl, 3, fd, cmd, arg);
 #endif
+#endif
 }
 libc_hidden_def(__libc_fcntl)
 
diff --git a/libc/sysdeps/linux/common/access.c b/libc/sysdeps/linux/common/access.c
index a075d42..ae3f2c6 100644
--- a/libc/sysdeps/linux/common/access.c
+++ b/libc/sysdeps/linux/common/access.c
@@ -9,4 +9,13 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+
+#if defined(__NR_access)
 _syscall2(int, access, const char *, pathname, int, mode)
+#elif defined(__NR_faccessat)
+#include <fcntl.h>
+int access(const char *pathname, int mode)
+{
+	return faccessat(AT_FDCWD, pathname, mode, 0);
+}
+#endif
diff --git a/libc/sysdeps/linux/common/chmod.c b/libc/sysdeps/linux/common/chmod.c
index 871e023..de4a903 100644
--- a/libc/sysdeps/linux/common/chmod.c
+++ b/libc/sysdeps/linux/common/chmod.c
@@ -10,7 +10,7 @@
 #include <sys/syscall.h>
 #include <sys/stat.h>
 
-
+#ifdef __NR_chmod
 #define __NR___syscall_chmod __NR_chmod
 static __inline__ _syscall2(int, __syscall_chmod, const char *, path, __kernel_mode_t, mode)
 
@@ -18,4 +18,12 @@ int chmod(const char *path, mode_t mode)
 {
 	return __syscall_chmod(path, mode);
 }
+#elif defined __NR_fchmodat
+#include <fcntl.h>
+int chmod(const char *path, mode_t mode)
+{
+	return fchmodat(AT_FDCWD, path, mode, 0);
+}
+#endif
+
 libc_hidden_def(chmod)
diff --git a/libc/sysdeps/linux/common/chown.c b/libc/sysdeps/linux/common/chown.c
index f2c60e0..e0a5c20 100644
--- a/libc/sysdeps/linux/common/chown.c
+++ b/libc/sysdeps/linux/common/chown.c
@@ -11,7 +11,6 @@
 #include <unistd.h>
 #include <bits/wordsize.h>
 
-
 #if (__WORDSIZE == 32 && defined(__NR_chown32)) || __WORDSIZE == 64
 # ifdef __NR_chown32
 #  undef __NR_chown
@@ -22,7 +21,8 @@ _syscall3(int, chown, const char *, path, uid_t, owner, gid_t, group)
 
 #else
 
-# define __NR___syscall_chown __NR_chown
+# if defined(__NR_chown)
+#  define __NR___syscall_chown __NR_chown
 static __inline__ _syscall3(int, __syscall_chown, const char *, path,
 		__kernel_uid_t, owner, __kernel_gid_t, group)
 
@@ -35,6 +35,18 @@ int chown(const char *path, uid_t owner, gid_t group)
 	}
 	return (__syscall_chown(path, owner, group));
 }
+# elif defined(__NR_fchownat)
+#include <fcntl.h>
+int chown(const char *path, uid_t owner, gid_t group)
+{
+	if (((owner + 1) > (uid_t) ((__kernel_uid_t) - 1U))
+		|| ((group + 1) > (gid_t) ((__kernel_gid_t) - 1U))) {
+		__set_errno(EINVAL);
+		return -1;
+	}
+	return fchownat(AT_FDCWD, path, owner, group, 0);
+}
+# endif
 #endif
 
 libc_hidden_def(chown)
diff --git a/libc/sysdeps/linux/common/dup2.c b/libc/sysdeps/linux/common/dup2.c
index 006f06b..b5e8cc0 100644
--- a/libc/sysdeps/linux/common/dup2.c
+++ b/libc/sysdeps/linux/common/dup2.c
@@ -9,7 +9,18 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <fcntl.h>
 
 
-_syscall2(int, dup2, int, oldfd, int, newfd)
+int
+dup2 (int fd, int fd2)
+{
+	/* For the degenerate case, check if the fd is valid (by trying to
+	   get the file status flags) and return it, or else return EBADF.  */
+	if (fd == fd2)
+		return __libc_fcntl(fd, F_GETFL, 0) < 0 ? -1 : fd;
+
+	return INLINE_SYSCALL(dup3, 3, fd, fd2, 0);
+}
+
 libc_hidden_def(dup2)
diff --git a/libc/sysdeps/linux/common/fstatat.c b/libc/sysdeps/linux/common/fstatat.c
index 33daa7c..21f1383 100644
--- a/libc/sysdeps/linux/common/fstatat.c
+++ b/libc/sysdeps/linux/common/fstatat.c
@@ -11,7 +11,7 @@
 #include "xstatconv.h"
 
 /* 64bit ports tend to favor newfstatat() */
-#ifdef __NR_newfstatat
+#if defined(__NR_newfstatat) && !defined(__NR_fstatat64)
 # define __NR_fstatat64 __NR_newfstatat
 #endif
 
diff --git a/libc/sysdeps/linux/common/fstatat64.c b/libc/sysdeps/linux/common/fstatat64.c
index 95627af..78a27b9 100644
--- a/libc/sysdeps/linux/common/fstatat64.c
+++ b/libc/sysdeps/linux/common/fstatat64.c
@@ -13,7 +13,7 @@
 #ifdef __UCLIBC_HAS_LFS__
 
 /* 64bit ports tend to favor newfstatat() */
-#ifdef __NR_newfstatat
+#if defined(__NR_newfstatat) && !defined(__NR_fstatat64)
 # define __NR_fstatat64 __NR_newfstatat
 #endif
 
diff --git a/libc/sysdeps/linux/common/fstatfs.c b/libc/sysdeps/linux/common/fstatfs.c
index fa0024a..ba8116c 100644
--- a/libc/sysdeps/linux/common/fstatfs.c
+++ b/libc/sysdeps/linux/common/fstatfs.c
@@ -22,9 +22,36 @@ extern int __REDIRECT_NTH (fstatfs, (int __fildes, struct statfs *__buf),
 # endif
 #endif
 
+#if defined(__NR_fstatfs)
 extern __typeof(fstatfs) __libc_fstatfs attribute_hidden;
 #define __NR___libc_fstatfs __NR_fstatfs
 _syscall2(int, __libc_fstatfs, int, fd, struct statfs *, buf)
+#elif defined(__NR_fstatfs64)
+#define __NR___syscall_fstatfs64 __NR_fstatfs64
+_syscall3(int, __syscall_fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 *, buf)
+int __libc_fstatfs(int fd, struct statfs *buf)
+{
+	struct statfs64 st;
+	int err;
+
+	err = __syscall_fstatfs64(fd, sizeof(st), &st);
+	if (err)
+		return err;
+
+	buf->f_type = st.f_type;
+	buf->f_bsize = st.f_bsize;
+	buf->f_blocks = st.f_blocks;
+	buf->f_bfree = st.f_bfree;
+	buf->f_bavail = st.f_bavail;
+	buf->f_files = st.f_files;
+	buf->f_ffree = st.f_ffree;
+	buf->f_fsid = st.f_fsid;
+	buf->f_namelen = st.f_namelen;
+	buf->f_frsize = st.f_frsize;
+
+	return 0;
+}
+#endif
 
 #if defined __UCLIBC_LINUX_SPECIFIC__
 weak_alias(__libc_fstatfs,fstatfs)
diff --git a/libc/sysdeps/linux/common/ftruncate.c b/libc/sysdeps/linux/common/ftruncate.c
index 3bdef3f..677581c 100644
--- a/libc/sysdeps/linux/common/ftruncate.c
+++ b/libc/sysdeps/linux/common/ftruncate.c
@@ -11,5 +11,12 @@
 #include <unistd.h>
 
 
+#ifdef __NR_ftruncate
 _syscall2(int, ftruncate, int, fd, __off_t, length)
+#elif defined(__NR_truncate64)
+int ftruncate(int fd, __off_t length)
+{
+	return ftruncate64(fd, length);
+}
+#endif
 libc_hidden_def(ftruncate)
diff --git a/libc/sysdeps/linux/common/getdents.c b/libc/sysdeps/linux/common/getdents.c
index 46f7b8e..28bdfc9 100644
--- a/libc/sysdeps/linux/common/getdents.c
+++ b/libc/sysdeps/linux/common/getdents.c
@@ -44,10 +44,12 @@ struct kernel_dirent
 
 ssize_t __getdents (int fd, char *buf, size_t nbytes) attribute_hidden;
 
+#ifdef __NR_getdents
 #define __NR___syscall_getdents __NR_getdents
 static __always_inline _syscall3(int, __syscall_getdents, int, fd, unsigned char *, kdirp, size_t, count)
+#endif
 
-#if defined __ASSUME_GETDENTS32_D_TYPE
+#if defined(__NR_getdents) && defined(__ASSUME_GETDENTS32_D_TYPE)
 
 ssize_t __getdents (int fd, char *buf, size_t nbytes)
 {
diff --git a/libc/sysdeps/linux/common/lchown.c b/libc/sysdeps/linux/common/lchown.c
index c0f8ce7..b66945f 100644
--- a/libc/sysdeps/linux/common/lchown.c
+++ b/libc/sysdeps/linux/common/lchown.c
@@ -21,6 +21,7 @@ _syscall3(int, lchown, const char *, path, uid_t, owner, gid_t, group)
 
 #else
 
+# if defined(__NR_lchown)
 # define __NR___syscall_lchown __NR_lchown
 static __inline__ _syscall3(int, __syscall_lchown, const char *, path,
 		__kernel_uid_t, owner, __kernel_gid_t, group)
@@ -34,5 +35,16 @@ int lchown(const char *path, uid_t owner, gid_t group)
 	}
 	return __syscall_lchown(path, owner, group);
 }
-
+# elif defined(__NR_fchownat)
+#include <fcntl.h>
+int lchown(const char *path, uid_t owner, gid_t group)
+{
+	if (((owner + 1) > (uid_t) ((__kernel_uid_t) - 1U))
+		|| ((group + 1) > (gid_t) ((__kernel_gid_t) - 1U))) {
+		__set_errno(EINVAL);
+		return -1;
+	}
+	return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW);
+}
+# endif
 #endif
diff --git a/libc/sysdeps/linux/common/link.c b/libc/sysdeps/linux/common/link.c
index b5e5536..b12feb3 100644
--- a/libc/sysdeps/linux/common/link.c
+++ b/libc/sysdeps/linux/common/link.c
@@ -9,4 +9,14 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+
+#if defined(__NR_link)
 _syscall2(int, link, const char *, oldpath, const char *, newpath)
+#elif defined(__NR_linkat)
+#include <fcntl.h>
+
+int link(const char * oldpath, const char * newpath)
+{
+	return linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
+}
+#endif
diff --git a/libc/sysdeps/linux/common/llseek.c b/libc/sysdeps/linux/common/llseek.c
index cd150ad..4e51fb0 100644
--- a/libc/sysdeps/linux/common/llseek.c
+++ b/libc/sysdeps/linux/common/llseek.c
@@ -11,6 +11,10 @@
 #include <sys/types.h>
 #include <sys/syscall.h>
 
+#if !defined __NR__llseek && defined __NR_llseek
+#define __NR__llseek __NR_llseek
+#endif
+
 #if defined __NR__llseek && defined __UCLIBC_HAS_LFS__
 
 loff_t lseek64(int fd, loff_t offset, int whence)
diff --git a/libc/sysdeps/linux/common/lstat.c b/libc/sysdeps/linux/common/lstat.c
index db72d1f..f8678c0 100644
--- a/libc/sysdeps/linux/common/lstat.c
+++ b/libc/sysdeps/linux/common/lstat.c
@@ -9,6 +9,7 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include "xstatconv.h"
 
@@ -26,6 +27,8 @@ int lstat(const char *file_name, struct stat *buf)
 	if (result == 0) {
 		__xstat32_conv(&kbuf, buf);
 	}
+#elif defined(__NR_fstatat64)
+	result = fstatat(AT_FDCWD, file_name, buf, AT_SYMLINK_NOFOLLOW);
 #else
 	struct kernel_stat kbuf;
 
diff --git a/libc/sysdeps/linux/common/mkdir.c b/libc/sysdeps/linux/common/mkdir.c
index fbc587d..b4eb890 100644
--- a/libc/sysdeps/linux/common/mkdir.c
+++ b/libc/sysdeps/linux/common/mkdir.c
@@ -11,6 +11,7 @@
 #include <sys/stat.h>
 
 
+#ifdef __NR_mkdir
 #define __NR___syscall_mkdir __NR_mkdir
 static __inline__ _syscall2(int, __syscall_mkdir, const char *, pathname,
 		__kernel_mode_t, mode)
@@ -19,4 +20,11 @@ int mkdir(const char *pathname, mode_t mode)
 {
 	return (__syscall_mkdir(pathname, mode));
 }
+#elif defined(__NR_mkdirat)
+#include <fcntl.h>
+int mkdir(const char *pathname, mode_t mode)
+{
+	return mkdirat(AT_FDCWD, pathname, mode);
+}
+#endif
 libc_hidden_def(mkdir)
diff --git a/libc/sysdeps/linux/common/mknod.c b/libc/sysdeps/linux/common/mknod.c
index b52c8c5..9954626 100644
--- a/libc/sysdeps/linux/common/mknod.c
+++ b/libc/sysdeps/linux/common/mknod.c
@@ -9,6 +9,7 @@
 
 #include <sys/syscall.h>
 #include <sys/stat.h>
+#include <fcntl.h>
 
 int mknod(const char *path, mode_t mode, dev_t dev)
 {
@@ -17,6 +18,10 @@ int mknod(const char *path, mode_t mode, dev_t dev)
 	/* We must convert the value to dev_t type used by the kernel.  */
 	k_dev = (dev) & ((1ULL << 32) - 1);
 
+#ifdef __NR_mknod
 	return INLINE_SYSCALL(mknod, 3, path, mode, (unsigned int)k_dev);
+#elif defined __NR_mknodat
+	return INLINE_SYSCALL(mknodat, 4, AT_FDCWD, path, mode, (unsigned int)k_dev);
+#endif
 }
 libc_hidden_def(mknod)
diff --git a/libc/sysdeps/linux/common/not-cancel.h b/libc/sysdeps/linux/common/not-cancel.h
index 9418417..ebea04a 100644
--- a/libc/sysdeps/linux/common/not-cancel.h
+++ b/libc/sysdeps/linux/common/not-cancel.h
@@ -19,12 +19,20 @@
    02111-1307 USA.  */
 
 #include <sysdep.h>
+#include <fcntl.h>
 
 /* Uncancelable open.  */
+#ifdef __NR_openat
+#define open_not_cancel(name, flags, mode) \
+   INLINE_SYSCALL (openat, 4, AT_FDCWD, (const char *) (name), (flags), (mode))
+#define open_not_cancel_2(name, flags) \
+   INLINE_SYSCALL (openat, 3, AT_FDCWD, (const char *) (name), (flags))
+#else
 #define open_not_cancel(name, flags, mode) \
    INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode))
 #define open_not_cancel_2(name, flags) \
    INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
+#endif
 
 /* Uncancelable close.  */
 #define close_not_cancel(fd) \
diff --git a/libc/sysdeps/linux/common/open.c b/libc/sysdeps/linux/common/open.c
index 9fb694d..bdb8e58 100644
--- a/libc/sysdeps/linux/common/open.c
+++ b/libc/sysdeps/linux/common/open.c
@@ -14,9 +14,16 @@
 #include <string.h>
 #include <sys/param.h>
 
+#ifdef __NR_open
 #define __NR___syscall_open __NR_open
 static __inline__ _syscall3(int, __syscall_open, const char *, file,
 		int, flags, __kernel_mode_t, mode)
+#endif
+#ifdef __NR_openat
+#define __NR___syscall_openat __NR_openat
+static __inline__ _syscall4(int, __syscall_openat, int, fd, const char *, file,
+		int, flags, __kernel_mode_t, mode)
+#endif
 
 int open(const char *file, int oflag, ...)
 {
@@ -29,7 +36,11 @@ int open(const char *file, int oflag, ...)
 		va_end(arg);
 	}
 
+#ifdef __NR_open
 	return __syscall_open(file, oflag, mode);
+#else
+	return __syscall_openat(AT_FDCWD, file, oflag, mode);
+#endif
 }
 #ifndef __LINUXTHREADS_OLD__
 libc_hidden_def(open)
diff --git a/libc/sysdeps/linux/common/pipe.c b/libc/sysdeps/linux/common/pipe.c
index 8eae27c..95e7ee0 100644
--- a/libc/sysdeps/linux/common/pipe.c
+++ b/libc/sysdeps/linux/common/pipe.c
@@ -10,6 +10,15 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-
+#if defined(__NR_pipe)
 _syscall1(int, pipe, int *, filedes)
+#elif defined(__NR_pipe2)
+#define __NR___syscall_pipe2 __NR_pipe2
+static __inline__ _syscall2(int, __syscall_pipe2, int *, filedes,
+		int, flag)
+int pipe(int filedes[2])
+{
+	return __syscall_pipe2(filedes, 0);
+}
+#endif
 libc_hidden_def(pipe)
diff --git a/libc/sysdeps/linux/common/readlink.c b/libc/sysdeps/linux/common/readlink.c
index ef9e835..26cf04f 100644
--- a/libc/sysdeps/linux/common/readlink.c
+++ b/libc/sysdeps/linux/common/readlink.c
@@ -10,5 +10,13 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
+#ifdef __NR_readlink
 _syscall3(ssize_t, readlink, const char *, path, char *, buf, size_t, bufsiz)
+#elif defined(__NR_readlinkat)
+#include <fcntl.h>
+ssize_t readlink(const char *path, char *buf, size_t bufsiz)
+{
+	return readlinkat(AT_FDCWD, path, buf, bufsiz);
+}
+#endif
 libc_hidden_def(readlink)
diff --git a/libc/sysdeps/linux/common/rename.c b/libc/sysdeps/linux/common/rename.c
index 9d8397a..1b26530 100644
--- a/libc/sysdeps/linux/common/rename.c
+++ b/libc/sysdeps/linux/common/rename.c
@@ -13,6 +13,7 @@
 #include <sys/param.h>
 #include <stdio.h>
 
+#if defined(__NR_rename)
 #define __NR___syscall_rename __NR_rename
 static __inline__ _syscall2(int, __syscall_rename, const char *, oldpath,
 		const char *, newpath)
@@ -21,4 +22,12 @@ int rename(const char * oldpath, const char * newpath)
 {
 	return __syscall_rename(oldpath, newpath);
 }
+#elif defined(__NR_renameat)
+#include <fcntl.h>
+
+int rename(const char * oldpath, const char * newpath)
+{
+	return renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
+}
+#endif
 
diff --git a/libc/sysdeps/linux/common/rmdir.c b/libc/sysdeps/linux/common/rmdir.c
index bad6654..85671ec 100644
--- a/libc/sysdeps/linux/common/rmdir.c
+++ b/libc/sysdeps/linux/common/rmdir.c
@@ -11,5 +11,14 @@
 #include <unistd.h>
 
 
+#if defined(__NR_rmdir)
 _syscall1(int, rmdir, const char *, pathname)
+#elif defined(__NR_unlinkat)
+#include <fcntl.h>
+
+int rmdir(const char * pathname)
+{
+	return unlinkat(AT_FDCWD, pathname, AT_REMOVEDIR);
+}
+#endif
 libc_hidden_def(rmdir)
diff --git a/libc/sysdeps/linux/common/stat.c b/libc/sysdeps/linux/common/stat.c
index 829f35a..fefe4df 100644
--- a/libc/sysdeps/linux/common/stat.c
+++ b/libc/sysdeps/linux/common/stat.c
@@ -9,6 +9,7 @@
 
 #include <sys/syscall.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include "xstatconv.h"
 
@@ -17,12 +18,14 @@
 int stat(const char *file_name, struct stat *buf)
 {
 	int result;
-#ifdef __NR_stat64
 	/* normal stat call has limited values for various stat elements
 	 * e.g. uid device major/minor etc.
 	 * so we use 64 variant if available
 	 * in order to get newer versions of stat elements
 	 */
+#ifdef __NR_fstatat64
+	result = fstatat(AT_FDCWD, file_name, buf, 0);
+#elif defined(__NR_stat64)
 	struct kernel_stat64 kbuf;
 	result = INLINE_SYSCALL(stat64, 2, file_name, &kbuf);
 	if (result == 0) {
diff --git a/libc/sysdeps/linux/common/statfs.c b/libc/sysdeps/linux/common/statfs.c
index d24bc9d..b43be6d 100644
--- a/libc/sysdeps/linux/common/statfs.c
+++ b/libc/sysdeps/linux/common/statfs.c
@@ -12,9 +12,37 @@
 #include <sys/param.h>
 #include <sys/vfs.h>
 
+#if defined(__NR_statfs)
 extern __typeof(statfs) __libc_statfs attribute_hidden;
 #define __NR___libc_statfs __NR_statfs
 _syscall2(int, __libc_statfs, const char *, path, struct statfs *, buf)
+#elif defined(__NR_statfs64)
+#define __NR___syscall_statfs64 __NR_statfs64
+_syscall2(int, __syscall_statfs64, const char *, path, struct statfs64 *, buf)
+
+int __libc_statfs(const char *path, struct statfs *buf)
+{
+	struct statfs64 st;
+	int err;
+
+	err = __syscall_statfs64(path, &st);
+	if (err)
+		return err;
+
+	buf->f_type = st.f_type;
+	buf->f_bsize = st.f_bsize;
+	buf->f_blocks = st.f_blocks;
+	buf->f_bfree = st.f_bfree;
+	buf->f_bavail = st.f_bavail;
+	buf->f_files = st.f_files;
+	buf->f_ffree = st.f_ffree;
+	buf->f_fsid = st.f_fsid;
+	buf->f_namelen = st.f_namelen;
+	buf->f_frsize = st.f_frsize;
+
+	return 0;
+}
+#endif
 
 #if defined __UCLIBC_LINUX_SPECIFIC__ || defined __UCLIBC_HAS_THREADS_NATIVE__
 /* statfs is used by NPTL, so it must exported in case */
diff --git a/libc/sysdeps/linux/common/stubs.c b/libc/sysdeps/linux/common/stubs.c
index a4c16b9..157da9a 100644
--- a/libc/sysdeps/linux/common/stubs.c
+++ b/libc/sysdeps/linux/common/stubs.c
@@ -150,10 +150,6 @@ make_stub(get_kernel_syms)
 make_stub(getpeername)
 #endif
 
-#if !defined(__NR_getpgrp) && (defined(__NR_getpgid) && (defined(__NR_getpid) || defined(__NR_getxpid)))
-make_stub(getpgrp)
-#endif
-
 #if !defined __NR_getsockname && !defined __NR_socketcall && defined __UCLIBC_HAS_SOCKET__
 make_stub(getsockname)
 #endif
@@ -403,7 +399,7 @@ make_stub(swapoff)
 make_stub(swapon)
 #endif
 
-#ifndef __NR_symlink
+#if !defined __NR_symlink && !defined __NR_symlinkat
 make_stub(symlink)
 #endif
 
@@ -443,7 +439,7 @@ make_stub(lutimes)
 # endif
 #endif
 
-#if !defined __NR_utime && !defined __NR_utimes
+#if !defined __NR_utime && !defined __NR_utimes && !defined __NR_utimensat
 /*make_stub(utime) obsoleted */
 make_stub(utimes)
 #endif
diff --git a/libc/sysdeps/linux/common/symlink.c b/libc/sysdeps/linux/common/symlink.c
index e53e8d4..5e24bdd 100644
--- a/libc/sysdeps/linux/common/symlink.c
+++ b/libc/sysdeps/linux/common/symlink.c
@@ -10,5 +10,14 @@
 #include <sys/syscall.h>
 #if defined __USE_BSD || defined __USE_UNIX98 || defined __USE_XOPEN2K
 #include <unistd.h>
+
+#ifdef __NR_symlink
 _syscall2(int, symlink, const char *, oldpath, const char *, newpath)
+#elif defined(__NR_symlinkat)
+#include <fcntl.h>
+int symlink(const char *oldpath, const char *newpath)
+{
+	return symlinkat(oldpath, AT_FDCWD, newpath);
+}
+#endif
 #endif
diff --git a/libc/sysdeps/linux/common/truncate.c b/libc/sysdeps/linux/common/truncate.c
index 2331bdd..596acb7 100644
--- a/libc/sysdeps/linux/common/truncate.c
+++ b/libc/sysdeps/linux/common/truncate.c
@@ -11,5 +11,12 @@
 #include <unistd.h>
 
 
+#ifdef __NR_truncate
 _syscall2(int, truncate, const char *, path, __off_t, length)
+#elif defined(__NR_truncate64)
+int truncate(const char *path, __off_t length)
+{
+	return truncate64(path, length);
+}
+#endif
 libc_hidden_def(truncate)
diff --git a/libc/sysdeps/linux/common/unlink.c b/libc/sysdeps/linux/common/unlink.c
index 513cdd5..6ae56cb 100644
--- a/libc/sysdeps/linux/common/unlink.c
+++ b/libc/sysdeps/linux/common/unlink.c
@@ -10,6 +10,13 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 
-
+#if defined(__NR_unlink)
 _syscall1(int, unlink, const char *, pathname)
+#elif defined(__NR_unlinkat)
+#include <fcntl.h>
+int unlink(const char *pathname)
+{
+	return unlinkat(AT_FDCWD, pathname, 0);
+}
+#endif
 libc_hidden_def(unlink)
diff --git a/libc/sysdeps/linux/common/ustat.c b/libc/sysdeps/linux/common/ustat.c
index e97fa76..1bcb581 100644
--- a/libc/sysdeps/linux/common/ustat.c
+++ b/libc/sysdeps/linux/common/ustat.c
@@ -11,6 +11,7 @@
 #include <sys/ustat.h>
 #include <sys/sysmacros.h>
 
+#ifdef __NR_ustat
 #define __NR___syscall_ustat __NR_ustat
 /* Kernel's fs/super.c defines this:
  * long sys_ustat(unsigned dev, struct ustat __user * ubuf),
@@ -24,3 +25,4 @@ int ustat(dev_t dev, struct ustat *ubuf)
 {
 	return __syscall_ustat(dev, ubuf);
 }
+#endif
diff --git a/libc/sysdeps/linux/common/utimes.c b/libc/sysdeps/linux/common/utimes.c
index 99d9202..c8abcd5 100644
--- a/libc/sysdeps/linux/common/utimes.c
+++ b/libc/sysdeps/linux/common/utimes.c
@@ -14,6 +14,28 @@
 
 #ifdef __NR_utimes
 _syscall2(int, utimes, const char *, file, const struct timeval *, tvp)
+#elif defined __NR_utimensat
+#include <stdlib.h>
+#include <fcntl.h>
+
+int utimes(const char *file, const struct timeval tvp[2])
+{
+	struct timespec ts[2];
+
+	if (tvp) {
+		if (tvp[0].tv_usec >= 1000000 || tvp[0].tv_usec < 0 ||
+		    tvp[1].tv_usec >= 1000000 || tvp[1].tv_usec < 0)
+			return -EINVAL;
+
+		ts[0].tv_sec = tvp[0].tv_sec;
+		ts[0].tv_nsec = 1000 * tvp[0].tv_usec;
+		ts[1].tv_sec = tvp[1].tv_sec;
+		ts[1].tv_nsec = 1000 * tvp[1].tv_usec;
+
+		return utimensat(AT_FDCWD, file, ts, 0);
+	} else
+		return utimensat(AT_FDCWD, file, NULL, 0);
+}
 #else
 #include <stdlib.h>
 
diff --git a/libpthread/linuxthreads.old/sysdeps/pthread/not-cancel.h b/libpthread/linuxthreads.old/sysdeps/pthread/not-cancel.h
index 80d33be..96ad271 100644
--- a/libpthread/linuxthreads.old/sysdeps/pthread/not-cancel.h
+++ b/libpthread/linuxthreads.old/sysdeps/pthread/not-cancel.h
@@ -20,12 +20,20 @@
 
 #include <sys/types.h>
 #include <sysdep.h>
+#include <fcntl.h>
 
 /* Uncancelable open.  */
+#ifdef __NR_openat
+#define open_not_cancel(name, flags, mode) \
+   INLINE_SYSCALL (openat, 4, AT_FDCWD, (const char *) (name), (flags), (mode))
+#define open_not_cancel_2(name, flags) \
+   INLINE_SYSCALL (openat, 3, AT_FDCWD, (const char *) (name), (flags))
+#else
 #define open_not_cancel(name, flags, mode) \
    INLINE_SYSCALL (open, 3, (const char *) (name), (flags), (mode))
 #define open_not_cancel_2(name, flags) \
    INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
+#endif
 
 /* Uncancelable openat.  */
 #if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
-- 
1.7.9.1



More information about the uClibc mailing list