support linux kernel apis (new archs) with old syscalls removed

such archs are expected to omit definitions of the SYS_* macros for
syscalls their kernels lack from arch/$ARCH/bits/syscall.h. the
preprocessor is then able to select the an appropriate implementation
for affected functions. two basic strategies are used on a
case-by-case basis:

where the old syscalls correspond to deprecated library-level
functions, the deprecated functions have been converted to wrappers
for the modern function, and the modern function has fallback code
(omitted at the preprocessor level on new archs) to make use of the
old syscalls if the new syscall fails with ENOSYS. this also improves
functionality on older kernels and eliminates the incentive to program
with deprecated library-level functions for the sake of compatibility
with older kernels.

in other situations where the old syscalls correspond to library-level
functions which are not deprecated but merely lack some new features,
such as the *at functions, the old syscalls are still used on archs
which support them. this may change at some point in the future if or
when fallback code is added to the new functions to make them usable
(possibly with reduced functionality) on old kernels.
This commit is contained in:
Rich Felker 2014-05-29 21:01:32 -04:00
parent 2e55da9118
commit dd5f50da6f
39 changed files with 267 additions and 29 deletions

View File

@ -1,6 +1,7 @@
#include <elf.h>
#include <poll.h>
#include <fcntl.h>
#include <signal.h>
#include "syscall.h"
#include "atomic.h"
#include "libc.h"
@ -48,7 +49,11 @@ void __init_libc(char **envp, char *pn)
&& !aux[AT_SECURE]) return;
struct pollfd pfd[3] = { {.fd=0}, {.fd=1}, {.fd=2} };
#ifdef SYS_poll
__syscall(SYS_poll, pfd, 3, 0);
#else
__syscall(SYS_ppoll, pfd, 3, &(struct timespec){0}, 0, _NSIG/8);
#endif
for (i=0; i<3; i++) if (pfd[i].revents&POLLNVAL)
if (__sys_open("/dev/null", O_RDWR)<0)
a_crash();

View File

@ -4,12 +4,16 @@
int epoll_create(int size)
{
return syscall(SYS_epoll_create, size);
return epoll_create1(0);
}
int epoll_create1(int flags)
{
return syscall(SYS_epoll_create1, flags);
int r = __syscall(SYS_epoll_create1, flags);
#ifdef SYS_epoll_create
if (r==-ENOSYS && !flags) r = __syscall(SYS_epoll_create, 1);
#endif
return __syscall_ret(r);
}
int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
@ -19,10 +23,14 @@ int epoll_ctl(int fd, int op, int fd2, struct epoll_event *ev)
int epoll_pwait(int fd, struct epoll_event *ev, int cnt, int to, const sigset_t *sigs)
{
return syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
int r = __syscall(SYS_epoll_pwait, fd, ev, cnt, to, sigs, _NSIG/8);
#ifdef SYS_epoll_wait
if (r==-ENOSYS && !sigs) r = __syscall(SYS_epoll_wait, fd, ev, cnt, to);
#endif
return __syscall_ret(r);
}
int epoll_wait(int fd, struct epoll_event *ev, int cnt, int to)
{
return syscall(SYS_epoll_wait, fd, ev, cnt, to);
return epoll_pwait(fd, ev, cnt, to, 0);
}

View File

@ -4,7 +4,11 @@
int eventfd(unsigned int count, int flags)
{
return syscall(flags ? SYS_eventfd2 : SYS_eventfd, count, flags);
int r = __syscall(SYS_eventfd2, count, flags);
#ifdef SYS_eventfd
if (r==-ENOSYS && !flags) r = __syscall(SYS_eventfd, count);
#endif
return __syscall_ret(r);
}
int eventfd_read(int fd, eventfd_t *value)

View File

@ -3,11 +3,15 @@
int inotify_init()
{
return syscall(SYS_inotify_init);
return inotify_init1(0);
}
int inotify_init1(int flags)
{
return syscall(SYS_inotify_init1, flags);
int r = __syscall(SYS_inotify_init1, flags);
#ifdef SYS_inotify_init
if (r==-ENOSYS && !flags) r = __syscall(SYS_inotify_init);
#endif
return __syscall_ret(r);
}
int inotify_add_watch(int fd, const char *pathname, uint32_t mask)

View File

@ -7,6 +7,7 @@
int signalfd(int fd, const sigset_t *sigs, int flags)
{
int ret = __syscall(SYS_signalfd4, fd, sigs, _NSIG/8, flags);
#ifdef SYS_signalfd
if (ret != -ENOSYS) return __syscall_ret(ret);
ret = __syscall(SYS_signalfd, fd, sigs, _NSIG/8);
if (ret >= 0) {
@ -15,5 +16,6 @@ int signalfd(int fd, const sigset_t *sigs, int flags)
if (flags & SFD_NONBLOCK)
__syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK);
}
#endif
return __syscall_ret(ret);
}

View File

@ -1,7 +1,10 @@
#include <sys/time.h>
#include "fcntl.h"
#include "syscall.h"
int __futimesat(int, const char *, const struct timeval [2]);
int utimes(const char *path, const struct timeval times[2])
{
return syscall(SYS_utimes, path, times);
return __futimesat(AT_FDCWD, path, times);
}

View File

@ -1,5 +1,6 @@
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include "syscall.h"
#include "libc.h"
#include "pthread_impl.h"
@ -16,7 +17,11 @@ pid_t fork(void)
sigset_t set;
__fork_handler(-1);
__block_all_sigs(&set);
#ifdef SYS_fork
ret = syscall(SYS_fork);
#else
ret = syscall(SYS_clone, SIGCHLD, 0);
#endif
if (libc.has_thread_pointer && !ret) {
pthread_t self = __pthread_self();
self->tid = self->pid = __syscall(SYS_getpid);

View File

@ -22,6 +22,20 @@ struct args {
void __get_handler_set(sigset_t *);
static int __sys_dup2(int old, int new)
{
#ifdef SYS_dup2
return __syscall(SYS_dup2, old, new);
#else
if (old==new) {
int r = __syscall(SYS_fcntl, old, F_GETFD);
return r<0 ? r : old;
} else {
return __syscall(SYS_dup3, old, new, 0);
}
#endif
}
static int child(void *args_vp)
{
int i, ret;
@ -92,14 +106,14 @@ static int child(void *args_vp)
goto fail;
break;
case FDOP_DUP2:
if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0)
if ((ret=__sys_dup2(op->srcfd, op->fd))<0)
goto fail;
break;
case FDOP_OPEN:
fd = __sys_open(op->path, op->oflag, op->mode);
if ((ret=fd) < 0) goto fail;
if (fd != op->fd) {
if ((ret=__syscall(SYS_dup2, fd, op->fd))<0)
if ((ret=__sys_dup2(fd, op->fd))<0)
goto fail;
__syscall(SYS_close, fd);
}

View File

@ -1,8 +1,16 @@
#include <poll.h>
#include <time.h>
#include <signal.h>
#include "syscall.h"
#include "libc.h"
int poll(struct pollfd *fds, nfds_t n, int timeout)
{
#ifdef SYS_poll
return syscall_cp(SYS_poll, fds, n, timeout);
#else
return syscall_cp(SYS_ppoll, fds, n, timeout>=0 ?
&((struct timespec){ .tv_sec = timeout/1000,
.tv_nsec = timeout%1000*1000000 }) : 0, 0, _NSIG/8);
#endif
}

View File

@ -1,8 +1,26 @@
#include <sys/select.h>
#include <signal.h>
#include <stdint.h>
#include <errno.h>
#include "syscall.h"
#include "libc.h"
int select(int n, fd_set *restrict rfds, fd_set *restrict wfds, fd_set *restrict efds, struct timeval *restrict tv)
{
#ifdef SYS_select
return syscall_cp(SYS_select, n, rfds, wfds, efds, tv);
#else
syscall_arg_t data[2] = { 0, _NSIG/8 };
struct timespec ts;
if (tv) {
if (tv->tv_sec < 0 || tv->tv_usec < 0)
return __syscall_ret(-EINVAL);
time_t extra_secs = tv->tv_usec / 1000000;
ts.tv_nsec = tv->tv_usec % 1000000 * 1000;
const time_t max_time = (1ULL<<8*sizeof(time_t)-1)-1;
ts.tv_sec = extra_secs > max_time - tv->tv_sec ?
max_time : tv->tv_sec + extra_secs;
}
return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, tv ? &ts : 0, data);
#endif
}

View File

@ -1,7 +1,12 @@
#include <sys/stat.h>
#include <fcntl.h>
#include "syscall.h"
int chmod(const char *path, mode_t mode)
{
#ifdef SYS_chmod
return syscall(SYS_chmod, path, mode);
#else
return syscall(SYS_fchmodat, AT_FDCWD, path, mode);
#endif
}

View File

@ -13,5 +13,9 @@ int fchmod(int fd, mode_t mode)
char buf[15+3*sizeof(int)];
__procfdname(buf, fd);
#ifdef SYS_chmod
return syscall(SYS_chmod, buf, mode);
#else
return syscall(SYS_fchmodat, AT_FDCWD, buf, mode);
#endif
}

View File

@ -28,8 +28,9 @@ int fchmodat(int fd, const char *path, mode_t mode, int flag)
}
__procfdname(proc, fd2);
if (!(ret = __syscall(SYS_stat, proc, &st)) && !S_ISLNK(st.st_mode))
ret = __syscall(SYS_chmod, proc, mode);
ret = __syscall(SYS_fstatat, AT_FDCWD, proc, &st, 0);
if (!ret && !S_ISLNK(st.st_mode))
ret = __syscall(SYS_fchmodat, AT_FDCWD, proc, mode);
__syscall(SYS_close, fd2);
return __syscall_ret(ret);

View File

@ -1,10 +1,23 @@
#define _GNU_SOURCE
#include <sys/time.h>
#include <sys/stat.h>
#include <errno.h>
#include "syscall.h"
#include "libc.h"
#ifdef SYS_futimesat
int futimesat(int dirfd, const char *pathname, const struct timeval times[2])
int __futimesat(int dirfd, const char *pathname, const struct timeval times[2])
{
return syscall(SYS_futimesat, dirfd, pathname, times);
struct timespec ts[2];
if (times) {
int i;
for (i=0; i<2; i++) {
if (times[i].tv_usec >= 1000000ULL)
return __syscall_ret(-EINVAL);
ts[i].tv_sec = times[i].tv_sec;
ts[i].tv_nsec = times[i].tv_usec * 1000;
}
}
return utimensat(dirfd, pathname, times ? ts : 0, 0);
}
#endif
weak_alias(__futimesat, futimesat);

View File

@ -1,10 +1,15 @@
#include <sys/stat.h>
#include <fcntl.h>
#include "syscall.h"
#include "libc.h"
int lstat(const char *restrict path, struct stat *restrict buf)
{
#ifdef SYS_lstat
return syscall(SYS_lstat, path, buf);
#else
return syscall(SYS_fstatat, AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
#endif
}
LFS64(lstat);

View File

@ -1,7 +1,12 @@
#include <sys/stat.h>
#include <fcntl.h>
#include "syscall.h"
int mkdir(const char *path, mode_t mode)
{
#ifdef SYS_mkdir
return syscall(SYS_mkdir, path, mode);
#else
return syscall(SYS_mkdirat, AT_FDCWD, path, mode);
#endif
}

View File

@ -1,7 +1,12 @@
#include <sys/stat.h>
#include <fcntl.h>
#include "syscall.h"
int mknod(const char *path, mode_t mode, dev_t dev)
{
#ifdef SYS_mknod
return syscall(SYS_mknod, path, mode, dev);
#else
return syscall(SYS_mknodat, AT_FDCWD, path, mode, dev);
#endif
}

View File

@ -1,10 +1,15 @@
#include <sys/stat.h>
#include <fcntl.h>
#include "syscall.h"
#include "libc.h"
int stat(const char *restrict path, struct stat *restrict buf)
{
#ifdef SYS_stat
return syscall(SYS_stat, path, buf);
#else
return syscall(SYS_fstatat, AT_FDCWD, path, buf, 0);
#endif
}
LFS64(stat);

View File

@ -1,7 +1,37 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <errno.h>
#include "syscall.h"
int utimensat(int fd, const char *path, const struct timespec times[2], int flags)
{
return syscall(SYS_utimensat, fd, path, times, flags);
int r = __syscall(SYS_utimensat, fd, path, times, flags);
#ifdef SYS_futimesat
if (r != -ENOSYS || flags) return __syscall_ret(r);
struct timeval *tv = 0, tmp[2];
if (times) {
int i;
tv = tmp;
for (i=0; i<2; i++) {
if (times[i].tv_nsec >= 1000000000ULL) {
if (times[i].tv_nsec == UTIME_NOW &&
times[1-i].tv_nsec == UTIME_NOW) {
tv = 0;
break;
}
if (times[i].tv_nsec == UTIME_OMIT)
return __syscall_ret(-ENOSYS);
return __syscall_ret(-EINVAL);
}
tmp[i].tv_sec = times[i].tv_sec;
tmp[i].tv_usec = times[i].tv_nsec / 1000;
}
}
r = __syscall(SYS_futimesat, fd, path, tv);
if (r != -ENOSYS || fd != AT_FDCWD) return __syscall_ret(r);
r = __syscall(SYS_utimes, path, tv);
#endif
return __syscall_ret(r);
}

View File

@ -1,9 +1,19 @@
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include "syscall.h"
int remove(const char *path)
{
int r = syscall(SYS_unlink, path);
return (r && errno == EISDIR) ? syscall(SYS_rmdir, path) : r;
#ifdef SYS_unlink
int r = __syscall(SYS_unlink, path);
#else
int r = __syscall(SYS_unlinkat, AT_FDCWD, path, 0);
#endif
#ifdef SYS_rmdir
if (r==-EISDIR) r = __syscall(SYS_rmdir, path);
#else
if (r==-EISDIR) r = __syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
#endif
return __syscall_ret(r);
}

View File

@ -1,7 +1,12 @@
#include <stdio.h>
#include <fcntl.h>
#include "syscall.h"
int rename(const char *old, const char *new)
{
#ifdef SYS_rename
return syscall(SYS_rename, old, new);
#else
return syscall(SYS_renameat, AT_FDCWD, old, AT_FDCWD, new);
#endif
}

View File

@ -36,7 +36,12 @@ char *tempnam(const char *dir, const char *pfx)
for (try=0; try<MAXTRIES; try++) {
__randname(s+l-6);
#ifdef SYS_lstat
r = __syscall(SYS_lstat, s, &(struct stat){0});
#else
r = __syscall(SYS_fstatat, AT_FDCWD, s,
&(struct stat){0}, AT_SYMLINK_NOFOLLOW);
#endif
if (r == -ENOENT) return strdup(s);
}
return 0;

View File

@ -17,7 +17,11 @@ FILE *tmpfile(void)
fd = sys_open(s, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd >= 0) {
f = __fdopen(fd, "w+");
#ifdef SYS_unlink
__syscall(SYS_unlink, s);
#else
__syscall(SYS_unlinkat, AT_FDCWD, s, 0);
#endif
return f;
}
}

View File

@ -17,7 +17,12 @@ char *tmpnam(char *buf)
int r;
for (try=0; try<MAXTRIES; try++) {
__randname(s+12);
#ifdef SYS_lstat
r = __syscall(SYS_lstat, s, &(struct stat){0});
#else
r = __syscall(SYS_fstatat, AT_FDCWD, s,
&(struct stat){0}, AT_SYMLINK_NOFOLLOW);
#endif
if (r == -ENOENT) return strcpy(buf ? buf : internal, s);
}
return 0;

View File

@ -1,14 +1,11 @@
#include <utime.h>
#include <sys/time.h>
#include "syscall.h"
#include <sys/stat.h>
#include <time.h>
#include <fcntl.h>
int utime(const char *path, const struct utimbuf *times)
{
if (times) {
struct timeval tv[2] = {
{ .tv_sec = times->actime },
{ .tv_sec = times->modtime } };
return syscall(SYS_utimes, path, tv);
}
return syscall(SYS_utimes, path, 0);
return utimensat(AT_FDCWD, path, times ? ((struct timespec [2]){
{ .tv_sec = times->actime }, { .tv_sec = times->modtime }})
: 0, 0);
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int access(const char *filename, int amode)
{
#ifdef SYS_access
return syscall(SYS_access, filename, amode);
#else
return syscall(SYS_faccessat, AT_FDCWD, filename, amode, 0);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int chown(const char *path, uid_t uid, gid_t gid)
{
#ifdef SYS_chown
return syscall(SYS_chown, path, uid, gid);
#else
return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, 0);
#endif
}

View File

@ -1,10 +1,20 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "syscall.h"
int dup2(int old, int new)
{
int r;
#ifdef SYS_dup2
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
#else
if (old==new) {
r = __syscall(SYS_fcntl, old, F_GETFD);
if (r >= 0) return old;
} else {
while ((r=__syscall(SYS_dup3, old, new, 0))==-EBUSY);
}
#endif
return __syscall_ret(r);
}

View File

@ -8,6 +8,7 @@
int __dup3(int old, int new, int flags)
{
int r;
#ifdef SYS_dup2
if (old==new) return __syscall_ret(-EINVAL);
if (flags & O_CLOEXEC) {
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
@ -15,6 +16,9 @@ int __dup3(int old, int new, int flags)
}
while ((r=__syscall(SYS_dup2, old, new))==-EBUSY);
if (flags & O_CLOEXEC) __syscall(SYS_fcntl, new, F_SETFD, FD_CLOEXEC);
#else
while ((r=__syscall(SYS_dup3, old, new, flags))==-EBUSY);
#endif
return __syscall_ret(r);
}

View File

@ -13,5 +13,10 @@ int fchown(int fd, uid_t uid, gid_t gid)
char buf[15+3*sizeof(int)];
__procfdname(buf, fd);
#ifdef SYS_chown
return syscall(SYS_chown, buf, uid, gid);
#else
return syscall(SYS_fchownat, AT_FDCWD, buf, uid, gid);
#endif
}

View File

@ -3,5 +3,5 @@
pid_t getpgrp(void)
{
return __syscall(SYS_getpgrp);
return __syscall(SYS_getpgid, 0);
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int lchown(const char *path, uid_t uid, gid_t gid)
{
#ifdef SYS_lchown
return syscall(SYS_lchown, path, uid, gid);
#else
return syscall(SYS_fchownat, AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int link(const char *existing, const char *new)
{
#ifdef SYS_link
return syscall(SYS_link, existing, new);
#else
return syscall(SYS_linkat, AT_FDCWD, existing, AT_FDCWD, new, 0);
#endif
}

View File

@ -1,8 +1,13 @@
#include <unistd.h>
#include <signal.h>
#include "syscall.h"
#include "libc.h"
int pause(void)
{
#ifdef SYS_pause
return syscall_cp(SYS_pause);
#else
return syscall_cp(SYS_ppoll, 0, 0, 0, 0);
#endif
}

View File

@ -3,5 +3,9 @@
int pipe(int fd[2])
{
#ifdef SYS_pipe
return syscall(SYS_pipe, fd);
#else
return syscall(SYS_pipe2, fd, 0);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize)
{
#ifdef SYS_readlink
return syscall(SYS_readlink, path, buf, bufsize);
#else
return syscall(SYS_readlinkat, AT_FDCWD, path, buf, bufsize);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int rmdir(const char *path)
{
#ifdef SYS_rmdir
return syscall(SYS_rmdir, path);
#else
return syscall(SYS_unlinkat, AT_FDCWD, path, AT_REMOVEDIR);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int symlink(const char *existing, const char *new)
{
#ifdef SYS_symlink
return syscall(SYS_symlink, existing, new);
#else
return syscall(SYS_symlinkat, existing, AT_FDCWD, new);
#endif
}

View File

@ -1,7 +1,12 @@
#include <unistd.h>
#include <fcntl.h>
#include "syscall.h"
int unlink(const char *path)
{
#ifdef SYS_unlink
return syscall(SYS_unlink, path);
#else
return syscall(SYS_unlinkat, AT_FDCWD, path, 0);
#endif
}