[2/3] syscalls: Add syscalls needed by arm64

Message ID 1383930736-20005-3-git-send-email-steve.capper@linaro.org
State New
Headers show

Commit Message

Steve Capper Nov. 8, 2013, 5:12 p.m.
arm64 uses generic syscalls, and does not include the "noat",
"noflags", and "deprecated" syscalls.
i.e. __ARCH_WANT_SYSCALL_{NO_AT|NO_FLAGS|DEPRECATED}

This patch adds the syscalls needed for klibc to run on arm64.

Signed-off-by: Steve Capper <steve.capper@linaro.org>
---
 usr/klibc/Kbuild       |  3 +++
 usr/klibc/SYSCALLS.def | 33 +++++++++++++++++----------------
 usr/klibc/access.c     | 12 ++++++++++++
 usr/klibc/chmod.c      | 17 +++++++++++++++++
 usr/klibc/chown.c      | 12 ++++++++++++
 usr/klibc/dup2.c       | 11 +++++++++++
 usr/klibc/lchown.c     | 12 ++++++++++++
 usr/klibc/link.c       | 12 ++++++++++++
 usr/klibc/lstat.c      | 17 +++++++++++++++++
 usr/klibc/mkdir.c      | 14 ++++++++++++++
 usr/klibc/mknod.c      | 14 ++++++++++++++
 usr/klibc/open64.c     | 22 ++++++++++++++++++++++
 usr/klibc/poll.c       | 21 +++++++++++++++++++++
 usr/klibc/readlink.c   | 12 ++++++++++++
 usr/klibc/rename.c     | 11 +++++++++++
 usr/klibc/rmdir.c      | 12 ++++++++++++
 usr/klibc/select.c     | 34 ++++++++++++++++++++++++++++++++++
 usr/klibc/stat.c       | 17 +++++++++++++++++
 usr/klibc/symlink.c    | 12 ++++++++++++
 usr/klibc/unlink.c     | 12 ++++++++++++
 usr/klibc/utimes.c     | 20 ++++++++++++++++++++
 21 files changed, 314 insertions(+), 16 deletions(-)
 create mode 100644 usr/klibc/access.c
 create mode 100644 usr/klibc/chmod.c
 create mode 100644 usr/klibc/chown.c
 create mode 100644 usr/klibc/dup2.c
 create mode 100644 usr/klibc/lchown.c
 create mode 100644 usr/klibc/link.c
 create mode 100644 usr/klibc/lstat.c
 create mode 100644 usr/klibc/mkdir.c
 create mode 100644 usr/klibc/mknod.c
 create mode 100644 usr/klibc/open64.c
 create mode 100644 usr/klibc/poll.c
 create mode 100644 usr/klibc/readlink.c
 create mode 100644 usr/klibc/rename.c
 create mode 100644 usr/klibc/rmdir.c
 create mode 100644 usr/klibc/select.c
 create mode 100644 usr/klibc/stat.c
 create mode 100644 usr/klibc/symlink.c
 create mode 100644 usr/klibc/unlink.c
 create mode 100644 usr/klibc/utimes.c

Comments

H. Peter Anvin Nov. 8, 2013, 7:37 p.m. | #1
On 11/08/2013 09:12 AM, Steve Capper wrote:
> diff --git a/usr/klibc/lstat.c b/usr/klibc/lstat.c
> new file mode 100644
> index 0000000..0282eec
> --- /dev/null
> +++ b/usr/klibc/lstat.c
> @@ -0,0 +1,17 @@
> +#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)
> +{
> +	int fd = open(path, O_RDONLY | O_PATH | O_NOFOLLOW);
> +	int ret = fstat(fd, buf);
> +	close(fd);
> +	return ret;
> +}
> +
> +#endif  /* __NR_lstat  */

  [...]

> diff --git a/usr/klibc/stat.c b/usr/klibc/stat.c
> new file mode 100644
> index 0000000..92343f1
> --- /dev/null
> +++ b/usr/klibc/stat.c
> @@ -0,0 +1,17 @@
> +#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)
> +{
> +	int fd = open(path, O_RDONLY);
> +	int ret = fstat(fd, buf);
> +	close(fd);
> +	return ret;
> +}
> +
> +#endif /* __NR_stat */

No.  Just... no.  Especially not O_RDONLY without O_PATH.

But do an implementation based on fstatat() instead.

	-hpa
H. Peter Anvin Nov. 8, 2013, 7:46 p.m. | #2
On 11/08/2013 09:12 AM, Steve Capper wrote:
> diff --git a/usr/klibc/open64.c b/usr/klibc/open64.c
> new file mode 100644
> index 0000000..6ca603e
> --- /dev/null
> +++ b/usr/klibc/open64.c
> @@ -0,0 +1,22 @@
> +/*
> + * open64.c
> + *
> + * 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 <sys/syscall.h>
> +
> +#if !defined(__NR_open) && _BITSIZE == 64
> +
> +__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

This applies equally to a 32-bit platform that doesn't define __NR_open,
except there we need to add O_LARGEFILE to the flags and call __openat
in order to not have to pull in openat.c as well.

I suggest merging this into open.c and making it look something like:

#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

#elif _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__)

... the rest of the current file ...
Steve Capper Nov. 11, 2013, 2:45 p.m. | #3
On Fri, Nov 08, 2013 at 11:37:43AM -0800, H. Peter Anvin wrote:
> On 11/08/2013 09:12 AM, Steve Capper wrote:
> > diff --git a/usr/klibc/lstat.c b/usr/klibc/lstat.c
> > new file mode 100644
> > index 0000000..0282eec
> > --- /dev/null
> > +++ b/usr/klibc/lstat.c
> > @@ -0,0 +1,17 @@
> > +#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)
> > +{
> > +	int fd = open(path, O_RDONLY | O_PATH | O_NOFOLLOW);
> > +	int ret = fstat(fd, buf);
> > +	close(fd);
> > +	return ret;
> > +}
> > +
> > +#endif  /* __NR_lstat  */
> 
>   [...]
> 
> > diff --git a/usr/klibc/stat.c b/usr/klibc/stat.c
> > new file mode 100644
> > index 0000000..92343f1
> > --- /dev/null
> > +++ b/usr/klibc/stat.c
> > @@ -0,0 +1,17 @@
> > +#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)
> > +{
> > +	int fd = open(path, O_RDONLY);
> > +	int ret = fstat(fd, buf);
> > +	close(fd);
> > +	return ret;
> > +}
> > +
> > +#endif /* __NR_stat */
> 
> No.  Just... no.  Especially not O_RDONLY without O_PATH.
> 
> But do an implementation based on fstatat() instead.
> 
> 	-hpa
> 
> 

Apologies.

I've redone stat and lstat to call fstatat. Also I have rewritten the
chmod call to use fchmodat.
Steve Capper Nov. 11, 2013, 2:54 p.m. | #4
On Fri, Nov 08, 2013 at 11:46:21AM -0800, H. Peter Anvin wrote:
> On 11/08/2013 09:12 AM, Steve Capper wrote:
> > diff --git a/usr/klibc/open64.c b/usr/klibc/open64.c
> > new file mode 100644
> > index 0000000..6ca603e
> > --- /dev/null
> > +++ b/usr/klibc/open64.c
> > @@ -0,0 +1,22 @@
> > +/*
> > + * open64.c
> > + *
> > + * 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 <sys/syscall.h>
> > +
> > +#if !defined(__NR_open) && _BITSIZE == 64
> > +
> > +__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
> 
> This applies equally to a 32-bit platform that doesn't define __NR_open,
> except there we need to add O_LARGEFILE to the flags and call __openat
> in order to not have to pull in openat.c as well.
> 
> I suggest merging this into open.c and making it look something like:
> 
> #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
> 
> #elif _BITSIZE == 32 && !defined(__i386__) && !defined(__m68k__)
> 
> ... the rest of the current file ...
> 

Yeah, I was in two minds about merging and this has tipped me over to
merging :-).

I've got a V2 patch set almost ready, I'm running it through some tests
and sanity checking it some more.

Thanks for the feedback,

Patch

diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index 2bef9ca..7e185e2 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -58,6 +58,9 @@  klib-y += vsnprintf.o snprintf.o vsprintf.o sprintf.o \
 	  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 open64.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 4630d14..c2f36e7 100644
--- a/usr/klibc/SYSCALLS.def
+++ b/usr/klibc/SYSCALLS.def
@@ -106,31 +106,31 @@  int swapoff(const char *);
 /*
  * 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 mkdir(const char *, mode_t);
+<?> int mkdir(const char *, mode_t);
 <?> int mkdirat(int, const char *, mode_t);
-int rmdir(const char *);
+<?> 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 *);
@@ -141,14 +141,15 @@  int readlink(const char *, char *, size_t);
 /* 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 @@  int getcwd::__getcwd(char *, size_t);
  */
 <!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 @@  int close(int);
 <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 @@  int pselect7::__pselect7(int, fd_set *, fd_set *, fd_set *, struct timespec *, c
 #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..d067752
--- /dev/null
+++ b/usr/klibc/chmod.c
@@ -0,0 +1,17 @@ 
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#ifndef __NR_chmod
+
+int chmod(const char *path, mode_t mode)
+{
+	int fd = open(path, O_RDONLY);
+	int ret = fchmod(fd, mode);
+	close(fd);
+	return ret;
+}
+
+#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..0282eec
--- /dev/null
+++ b/usr/klibc/lstat.c
@@ -0,0 +1,17 @@ 
+#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)
+{
+	int fd = open(path, O_RDONLY | O_PATH | O_NOFOLLOW);
+	int ret = fstat(fd, buf);
+	close(fd);
+	return ret;
+}
+
+#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/open64.c b/usr/klibc/open64.c
new file mode 100644
index 0000000..6ca603e
--- /dev/null
+++ b/usr/klibc/open64.c
@@ -0,0 +1,22 @@ 
+/*
+ * open64.c
+ *
+ * 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 <sys/syscall.h>
+
+#if !defined(__NR_open) && _BITSIZE == 64
+
+__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
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..92343f1
--- /dev/null
+++ b/usr/klibc/stat.c
@@ -0,0 +1,17 @@ 
+#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)
+{
+	int fd = open(path, O_RDONLY);
+	int ret = fstat(fd, buf);
+	close(fd);
+	return ret;
+}
+
+#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 */