[klibc] syscalls: Add syscalls needed by arm64

arm64 uses generic syscalls, and does not include the "noat",
"noflags", and "deprecated" syscalls.

This patch adds substitution functions for system calls not available
on arm64.

Originally-by: Neil Williams <codehelp@debian.org>
Originally-by: Anil Singhar <anil.singhar@linaro.org>
Signed-off-by: Steve Capper <steve.capper@linaro.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index 2bef9ca..40d43c7 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -58,6 +58,9 @@
 	  inet/inet_ntoa.o inet/inet_aton.o inet/inet_addr.o \
 	  inet/inet_ntop.o inet/inet_pton.o inet/bindresvport.o \
 	  send.o recv.o \
+	  access.o chmod.o chown.o dup2.o mknod.o poll.o rename.o stat.o \
+	  lchown.o link.o rmdir.o unlink.o utimes.o lstat.o mkdir.o \
+	  readlink.o select.o symlink.o pipe.o \
 	  ctype/isalnum.o ctype/isalpha.o ctype/isascii.o \
 	  ctype/isblank.o ctype/iscntrl.o ctype/isdigit.o \
 	  ctype/isgraph.o ctype/islower.o ctype/isprint.o \
diff --git a/usr/klibc/SYSCALLS.def b/usr/klibc/SYSCALLS.def
index 55d8e36..12f57ac 100644
--- a/usr/klibc/SYSCALLS.def
+++ b/usr/klibc/SYSCALLS.def
@@ -106,34 +106,34 @@
 /*
  * Inode-related system calls
  */
-int access(const char *, int);
+<?> int access(const char *, int);
 int faccessat(int, const char *, int, int);
-int link(const char *, const char *);
+<?> int link(const char *, const char *);
 <?> int linkat(int, const char *, int, const char *, int);
-int unlink(const char *);
+<?> int unlink(const char *);
 <?> int unlinkat(int, const char *, int);
 int chdir(const char *);
 int fchdir(int);
-int rename(const char *, const char *);
+<?> int rename(const char *, const char *);
 <?> int renameat(int, const char *, int, const char *);
-int mknod(const char *, mode_t, dev_t);
+<?> int mknod(const char *, mode_t, dev_t);
 <?> int mknodat(int, const char *, mode_t, dev_t);
-int chmod(const char *, mode_t);
+<?> int chmod(const char *, mode_t);
 int fchmod(int, mode_t);
 <?> int fchmodat(int, const char *, mode_t, int);
-int mkdir(const char *, mode_t);
+<?> int mkdir(const char *, mode_t);
 <?> int mkdirat(int, const char *, mode_t);
-int rmdir(const char *);
-<!alpha,ia64,mips,mips64,sh,sparc,sparc64> int pipe(int *);
+<?> int rmdir(const char *);
+<?!alpha,ia64,mips,mips64,sh,sparc,sparc64> int pipe(int *);
 int pipe2(int *, int);
 mode_t umask(mode_t);
 int chroot(const char *);
-int symlink(const char *, const char *);
+<?> int symlink(const char *, const char *);
 <?> int symlinkat(const char *, int, const char *);
-int readlink(const char *, char *, size_t);
+<?> int readlink(const char *, char *, size_t);
 <?> int readlinkat(int, const char *, char *, int);
-<!ppc64> int stat64,stat::stat(const char *, struct stat *);
-<!ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
+<?!ppc64> int stat64,stat::stat(const char *, struct stat *);
+<?!ppc64> int lstat64,lstat::lstat(const char *, struct stat *);
 <!ppc64> int fstat64,fstat::fstat(int, struct stat *);
 <ppc64> int stat::stat(const char *, struct stat *);
 <ppc64> int lstat::lstat(const char *, struct stat *);
@@ -141,14 +141,15 @@
 /* XXX: Is this right?! */
 <?> int fstatat64,newfstatat,fstatat::fstatat(int, const char *, struct stat *, int);
 int getdents64,getdents::getdents(unsigned int, struct dirent *, unsigned int);
-int chown32,chown::chown(const char *, uid_t, gid_t);
+<?> int chown32,chown::chown(const char *, uid_t, gid_t);
 int fchown32,fchown::fchown(int, uid_t, gid_t);
 <?> int fchownat(int, const char *, uid_t, gid_t, int);
-int lchown32,lchown::lchown(const char *, uid_t, gid_t);
+<?> int lchown32,lchown::lchown(const char *, uid_t, gid_t);
 int getcwd::__getcwd(char *, size_t);
 <?> int utime(const char *, const struct utimbuf *);
 <?> int utimes(const char *, const struct timeval *);
 <?> int futimesat(int, const char *, const struct timeval *);
+<?> int utimensat(int, const char *, const struct timespec *, int);
 <?> int inotify_init();
 <?> int inotify_add_watch(int, const char *, __u32);
 <?> int inotify_rm_watch(int, __u32);
@@ -158,7 +159,7 @@
  */
 <!i386,m68k,64> int open::__open(const char *, int, mode_t);
 <?!i386,m68k,64> int openat::__openat(int, const char *, int, mode_t);
-<64> int open(const char *, int, mode_t);
+<?64> int open(const char *, int, mode_t);
 <64> int openat(int, const char *, int, mode_t);
 ssize_t read(int, void *, size_t);
 ssize_t write(int, const void *, size_t);
@@ -166,14 +167,14 @@
 <64> off_t lseek(int, off_t, int);
 <32> int _llseek::__llseek(int, unsigned long, unsigned long, off_t *, int);
 int dup(int);
-int dup2(int, int);
+<?> int dup2(int, int);
 int dup3(int, int, int);
 <i386> int fcntl64@varadic::fcntl(int, int, unsigned long);
 <ppc64> int fcntl(int, int, unsigned long);
 <!i386,ppc64> int fcntl64,fcntl::fcntl(int, int, unsigned long);
 int ioctl(int, int, void *);
 int flock(int, int);
-int _newselect,select::select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+<?> int _newselect,select::select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
 #if defined(__NR_pselect) && !_KLIBC_USE_RT_SIG
 int pselect(int, fd_set *, fd_set *, fd_set *, const struct timespec *, const sigset_t *);
 #elif defined(__NR_pselect7)
@@ -181,7 +182,7 @@
 #elif defined(__NR_pselect6)
 int pselect6::__pselect6(int, fd_set *, fd_set *, fd_set *, struct timespec *, const struct __pselect6 *);
 #endif
-int poll(struct pollfd *, nfds_t, long);
+<?> int poll(struct pollfd *, nfds_t, long);
 <?> int ppoll::__ppoll(struct pollfd *, nfds_t, struct timespec *, const sigset_t *, size_t);
 int fsync(int);
 int fdatasync,fsync::fdatasync(int);
diff --git a/usr/klibc/access.c b/usr/klibc/access.c
new file mode 100644
index 0000000..0f24856
--- /dev/null
+++ b/usr/klibc/access.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_access
+
+int access(const char *pathname, int mode)
+{
+	return faccessat(AT_FDCWD, pathname, mode, 0);
+}
+
+#endif  /* __NR_access */
diff --git a/usr/klibc/chmod.c b/usr/klibc/chmod.c
new file mode 100644
index 0000000..b5129e6
--- /dev/null
+++ b/usr/klibc/chmod.c
@@ -0,0 +1,13 @@
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_chmod
+
+int chmod(const char *path, mode_t mode)
+{
+	return fchmodat(AT_FDCWD, path, mode, 0);
+}
+
+#endif  /* __NR_chmod */
diff --git a/usr/klibc/chown.c b/usr/klibc/chown.c
new file mode 100644
index 0000000..089cfc5
--- /dev/null
+++ b/usr/klibc/chown.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_chown
+
+int chown(const char *path, uid_t owner, gid_t group)
+{
+	return fchownat(AT_FDCWD, path, owner, group, 0);
+}
+
+#endif  /* __NR_chown  */
diff --git a/usr/klibc/dup2.c b/usr/klibc/dup2.c
new file mode 100644
index 0000000..67e2171
--- /dev/null
+++ b/usr/klibc/dup2.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_dup2
+
+int dup2(int fd, int fd2)
+{
+	return dup3(fd, fd2, 0);
+}
+
+#endif /* __NR_dup2 */
diff --git a/usr/klibc/lchown.c b/usr/klibc/lchown.c
new file mode 100644
index 0000000..9a9e1e1
--- /dev/null
+++ b/usr/klibc/lchown.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_lchown
+
+int lchown(const char *path, uid_t owner, gid_t group)
+{
+	return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW);
+}
+
+#endif /* __NR_lchown */
diff --git a/usr/klibc/link.c b/usr/klibc/link.c
new file mode 100644
index 0000000..1d4b70e
--- /dev/null
+++ b/usr/klibc/link.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_link
+
+int link(const char *oldpath, const char *newpath)
+{
+	return linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
+}
+
+#endif  /* __NR_link */
diff --git a/usr/klibc/lstat.c b/usr/klibc/lstat.c
new file mode 100644
index 0000000..3288a33
--- /dev/null
+++ b/usr/klibc/lstat.c
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_lstat
+
+int lstat(const char *path, struct stat *buf)
+{
+	return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
+}
+
+#endif  /* __NR_lstat  */
diff --git a/usr/klibc/mkdir.c b/usr/klibc/mkdir.c
new file mode 100644
index 0000000..27673e3
--- /dev/null
+++ b/usr/klibc/mkdir.c
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_mkdir
+
+int mkdir(const char *pathname, mode_t mode)
+{
+	return mkdirat(AT_FDCWD, pathname, mode);
+}
+
+#endif /* __NR_mkdir */
diff --git a/usr/klibc/mknod.c b/usr/klibc/mknod.c
new file mode 100644
index 0000000..727505f
--- /dev/null
+++ b/usr/klibc/mknod.c
@@ -0,0 +1,14 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_mknod
+
+int mknod(const char *pathname, mode_t mode, dev_t dev)
+{
+	return mknodat(AT_FDCWD, pathname, mode, dev);
+}
+
+#endif  /* __NR_mknod  */
diff --git a/usr/klibc/open.c b/usr/klibc/open.c
index 126f6db..5305c3d 100644
--- a/usr/klibc/open.c
+++ b/usr/klibc/open.c
@@ -3,14 +3,39 @@
  *
  * On 32-bit platforms we need to pass O_LARGEFILE to the open()
  * system call, to indicate that we're 64-bit safe.
+ *
+ * For 64 bit systems without the open syscall, pass straight
+ * through into openat.
  */
 
 #define _KLIBC_IN_OPEN_C
 #include <unistd.h>
 #include <fcntl.h>
 #include <bitsize.h>
+#include <sys/syscall.h>
 
-#if _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__)
+#ifndef __NR_open
+#if _BITSIZE == 32
+
+extern int __openat(int, const char *, int, mode_t);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+	return __openat(AT_FDCWD, pathname, flags | O_LARGEFILE, mode);
+}
+
+#else
+
+__extern int openat(int, const char *, int, ...);
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+	return openat(AT_FDCWD, pathname, flags, mode);
+}
+
+#endif /* _BITSIZE == 32 */
+
+#elif _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__)
 
 extern int __open(const char *, int, mode_t);
 
@@ -19,4 +44,4 @@
 	return __open(pathname, flags | O_LARGEFILE, mode);
 }
 
-#endif
+#endif /* __NR_open */
diff --git a/usr/klibc/pipe.c b/usr/klibc/pipe.c
new file mode 100644
index 0000000..dfaed9e
--- /dev/null
+++ b/usr/klibc/pipe.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_pipe
+
+int pipe(int pipefd[2])
+{
+	return pipe2(pipefd, 0);
+}
+
+#endif  /* __NR_pipe */
diff --git a/usr/klibc/poll.c b/usr/klibc/poll.c
new file mode 100644
index 0000000..69da693
--- /dev/null
+++ b/usr/klibc/poll.c
@@ -0,0 +1,21 @@
+#include <errno.h>
+#include <sys/poll.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_poll
+
+int poll (struct pollfd *fds, nfds_t nfds, long timeout)
+{
+	struct timespec timeout_ts;
+	struct timespec *timeout_ts_p = NULL;
+
+	if (timeout >= 0) {
+		timeout_ts.tv_sec = timeout / 1000;
+		timeout_ts.tv_nsec = (timeout % 1000) * 1000000;
+		timeout_ts_p = &timeout_ts;
+	}
+
+	return ppoll(fds, nfds, timeout_ts_p, 0);
+}
+
+#endif /* __NR_poll */
diff --git a/usr/klibc/readlink.c b/usr/klibc/readlink.c
new file mode 100644
index 0000000..0e67442
--- /dev/null
+++ b/usr/klibc/readlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_readlink
+
+int readlink(const char *path, char *buf, size_t bufsiz)
+{
+	return readlinkat(AT_FDCWD, path, buf, bufsiz);
+}
+
+#endif /* __NR_readlink */
diff --git a/usr/klibc/rename.c b/usr/klibc/rename.c
new file mode 100644
index 0000000..587c26f
--- /dev/null
+++ b/usr/klibc/rename.c
@@ -0,0 +1,11 @@
+#include <fcntl.h>
+#include <stdio.h>
+
+#ifndef __NR_rename
+
+int rename(const char *oldpath, const char *newpath)
+{
+	return renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
+}
+
+#endif /* __NR_rename */
diff --git a/usr/klibc/rmdir.c b/usr/klibc/rmdir.c
new file mode 100644
index 0000000..94ae5f2
--- /dev/null
+++ b/usr/klibc/rmdir.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_rmdir
+
+int rmdir(const char *pathname)
+{
+	return unlinkat(AT_FDCWD, pathname, AT_REMOVEDIR);
+}
+
+#endif /* __NR_rmdir */
diff --git a/usr/klibc/select.c b/usr/klibc/select.c
new file mode 100644
index 0000000..e416794
--- /dev/null
+++ b/usr/klibc/select.c
@@ -0,0 +1,34 @@
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <sys/syscall.h>
+
+#if !defined(__NR_select) && !defined(__NR__newselect)
+
+struct __pselect6;
+__extern int __pselect6(int, fd_set *, fd_set *, fd_set *,
+                        const struct timespec *, const struct __pselect6 *);
+
+int select(int nfds, fd_set *readfds, fd_set *writefds,
+			fd_set *exceptfds, struct timeval *timeout)
+{
+	int result;
+	struct timespec ts;
+
+	if (timeout) {
+		ts.tv_sec = timeout->tv_sec;
+		ts.tv_nsec = timeout->tv_usec * 1000;
+	}
+
+	result = __pselect6(nfds, readfds, writefds, exceptfds, &ts, NULL);
+
+	if (timeout) {
+		timeout->tv_sec = ts.tv_sec;
+		timeout->tv_usec = ts.tv_nsec / 1000;
+	}
+
+	return result;
+}
+
+#endif
diff --git a/usr/klibc/stat.c b/usr/klibc/stat.c
new file mode 100644
index 0000000..65063b0
--- /dev/null
+++ b/usr/klibc/stat.c
@@ -0,0 +1,14 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_stat
+
+int stat(const char *path, struct stat *buf)
+{
+	return fstatat(AT_FDCWD, path, buf, 0);
+}
+
+#endif /* __NR_stat */
diff --git a/usr/klibc/symlink.c b/usr/klibc/symlink.c
new file mode 100644
index 0000000..080394f
--- /dev/null
+++ b/usr/klibc/symlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_symlink
+
+int symlink(const char *oldpath, const char *newpath)
+{
+	return symlinkat(oldpath, AT_FDCWD, newpath);
+}
+
+#endif /* __NR_symlink */
diff --git a/usr/klibc/unlink.c b/usr/klibc/unlink.c
new file mode 100644
index 0000000..6dfe66c
--- /dev/null
+++ b/usr/klibc/unlink.c
@@ -0,0 +1,12 @@
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_unlink
+
+int unlink(const char *pathname)
+{
+	return unlinkat(AT_FDCWD, pathname, 0);
+}
+
+#endif  /* __NR_unlink */
diff --git a/usr/klibc/utimes.c b/usr/klibc/utimes.c
new file mode 100644
index 0000000..fd378a6
--- /dev/null
+++ b/usr/klibc/utimes.c
@@ -0,0 +1,20 @@
+#include <fcntl.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_utimes
+
+int utimes(const char *file, const struct timeval tvp[2])
+{
+	struct timespec ts[2];
+
+	if (tvp) {
+		ts->tv_sec = tvp->tv_sec;
+		ts->tv_nsec = tvp->tv_usec * 1000;
+	}
+
+	return utimensat(AT_FDCWD, file, &ts[0], 0);
+}
+
+#endif /* __NR_utimes */