/* * Copyright (C) 2005 Jan Kiszka . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "internal.h" /* support for very old c libraries not supporting O_TMPFILE */ #ifndef O_TMPFILE #define O_TMPFILE (020000000 | 0200000) #endif static inline int set_errno(int ret) { if (ret >= 0) return ret; errno = -ret; return -1; } static int do_open(const char *path, int oflag, mode_t mode) { int fd, oldtype; /* * Don't dereference path, as it might be invalid. Leave it to * the kernel service. */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); fd = XENOMAI_SYSCALL2( sc_cobalt_open, path, oflag); pthread_setcanceltype(oldtype, NULL); if (fd < 0) { if (fd != -EADV && fd != -ENOSYS) return set_errno(fd); fd = __STD(open(path, oflag, mode)); } return fd; } COBALT_IMPL(int, open, (const char *path, int oflag, ...)) { mode_t mode = 0; va_list ap; if ((oflag & O_CREAT) || (oflag & O_TMPFILE) == O_TMPFILE) { va_start(ap, oflag); mode = va_arg(ap, int); va_end(ap); } return do_open(path, oflag, mode); } COBALT_IMPL(int, open64, (const char *path, int oflag, ...)) { mode_t mode = 0; va_list ap; if ((oflag & O_CREAT) || (oflag & O_TMPFILE) == O_TMPFILE) { va_start(ap, oflag); mode = va_arg(ap, int); va_end(ap); } return do_open(path, oflag | O_LARGEFILE, mode); } COBALT_IMPL(int, __open_2, (const char *path, int oflag)) { /* __open_2() from glibc adds a runtime precondition test for the 'oflag' * parameter to the functionality of open(). It may be used when the macro * _FORTIFY_SOURCE is defined when compiling the application code. */ if (__OPEN_NEEDS_MODE(oflag)) { const char *msg = "invalid open call: O_CREAT or O_TMPFILE without mode\n"; ssize_t n = __STD(write(STDERR_FILENO, msg, strlen(msg))); (void)n; abort(); } return do_open(path, oflag, 0); } COBALT_IMPL(int, __open64_2, (const char *path, int oflag)) { /* just like __open_2() and open64() */ if (__OPEN_NEEDS_MODE(oflag)) { const char *msg = "invalid open64 call: O_CREAT or O_TMPFILE without mode\n"; ssize_t n = __STD(write(STDERR_FILENO, msg, strlen(msg))); (void)n; abort(); } return do_open(path, oflag | O_LARGEFILE, 0); } COBALT_IMPL(int, socket, (int protocol_family, int socket_type, int protocol)) { int s; s = XENOMAI_SYSCALL3(sc_cobalt_socket, protocol_family, socket_type, protocol); if (s < 0) { if (s != -EAFNOSUPPORT && s != -EPROTONOSUPPORT && s != -ENOSYS) return set_errno(s); s = __STD(socket(protocol_family, socket_type, protocol)); } return s; } COBALT_IMPL(int, close, (int fd)) { int oldtype; int ret; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL1(sc_cobalt_close, fd); pthread_setcanceltype(oldtype, NULL); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(close(fd)); } static int do_ioctl(int fd, unsigned int request, void *arg) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL3(sc_cobalt_ioctl, fd, request, arg); pthread_setcanceltype(oldtype, NULL); return ret; } COBALT_IMPL(int, fcntl, (int fd, int cmd, ...)) { va_list ap; long arg; int ret; va_start(ap, cmd); arg = va_arg(ap, long); va_end(ap); ret = XENOMAI_SYSCALL3(sc_cobalt_fcntl, fd, cmd, arg); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(fcntl(fd, cmd, arg)); } COBALT_IMPL(int, ioctl, (int fd, unsigned int request, ...)) { va_list ap; void *arg; int ret; va_start(ap, request); arg = va_arg(ap, void *); va_end(ap); ret = do_ioctl(fd, request, arg); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(ioctl(fd, request, arg)); } COBALT_IMPL(ssize_t, read, (int fd, void *buf, size_t nbyte)) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL3(sc_cobalt_read, fd, buf, nbyte); pthread_setcanceltype(oldtype, NULL); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(read(fd, buf, nbyte)); } COBALT_IMPL(ssize_t, write, (int fd, const void *buf, size_t nbyte)) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL3(sc_cobalt_write, fd, buf, nbyte); pthread_setcanceltype(oldtype, NULL); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(write(fd, buf, nbyte)); } static ssize_t do_recvmsg(int fd, struct msghdr *msg, int flags) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL3(sc_cobalt_recvmsg, fd, msg, flags); pthread_setcanceltype(oldtype, NULL); return ret; } COBALT_IMPL(ssize_t, recvmsg, (int fd, struct msghdr *msg, int flags)) { int ret; ret = do_recvmsg(fd, msg, flags); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(recvmsg(fd, msg, flags)); } COBALT_IMPL(int, recvmmsg, (int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout)) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); #ifdef __USE_TIME_BITS64 ret = XENOMAI_SYSCALL5(sc_cobalt_recvmmsg64, fd, msgvec, vlen, flags, timeout); #else ret = XENOMAI_SYSCALL5(sc_cobalt_recvmmsg, fd, msgvec, vlen, flags, timeout); #endif pthread_setcanceltype(oldtype, NULL); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(recvmmsg(fd, msgvec, vlen, flags, timeout)); } static ssize_t do_sendmsg(int fd, const struct msghdr *msg, int flags) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL3(sc_cobalt_sendmsg, fd, msg, flags); pthread_setcanceltype(oldtype, NULL); return ret; } COBALT_IMPL(ssize_t, sendmsg, (int fd, const struct msghdr *msg, int flags)) { int ret; ret = do_sendmsg(fd, msg, flags); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(sendmsg(fd, msg, flags)); } COBALT_IMPL(int, sendmmsg, (int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags)) { int ret, oldtype; pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype); ret = XENOMAI_SYSCALL4(sc_cobalt_sendmmsg, fd, msgvec, vlen, flags); pthread_setcanceltype(oldtype, NULL); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(sendmmsg(fd, msgvec, vlen, flags)); } COBALT_IMPL(ssize_t, recvfrom, (int fd, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen)) { struct iovec iov = { .iov_base = buf, .iov_len = len, }; struct msghdr msg = { .msg_name = from, .msg_namelen = from != NULL ? *fromlen : 0, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, }; int ret; ret = do_recvmsg(fd, &msg, flags); if (ret != -EADV && ret != -ENOSYS) { if (ret < 0) return set_errno(ret); if (from) *fromlen = msg.msg_namelen; return ret; } return __STD(recvfrom(fd, buf, len, flags, from, fromlen)); } COBALT_IMPL(ssize_t, sendto, (int fd, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen)) { struct iovec iov = { .iov_base = (void *)buf, .iov_len = len, }; struct msghdr msg = { .msg_name = (struct sockaddr *)to, .msg_namelen = tolen, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, }; int ret; ret = do_sendmsg(fd, &msg, flags); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(sendto(fd, buf, len, flags, to, tolen)); } COBALT_IMPL(ssize_t, recv, (int fd, void *buf, size_t len, int flags)) { struct iovec iov = { .iov_base = (void *)buf, .iov_len = len, }; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, }; int ret; ret = do_recvmsg(fd, &msg, flags); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(recv(fd, buf, len, flags)); } COBALT_IMPL(ssize_t, send, (int fd, const void *buf, size_t len, int flags)) { struct iovec iov = { .iov_base = (void *)buf, .iov_len = len, }; struct msghdr msg = { .msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, }; int ret; ret = do_sendmsg(fd, &msg, flags); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(send(fd, buf, len, flags)); } COBALT_IMPL(int, getsockopt, (int fd, int level, int optname, void *optval, socklen_t *optlen)) { struct _rtdm_getsockopt_args args = { level, optname, optval, optlen }; int ret; ret = do_ioctl(fd, _RTIOC_GETSOCKOPT, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(getsockopt(fd, level, optname, optval, optlen)); } COBALT_IMPL(int, setsockopt, (int fd, int level, int optname, const void *optval, socklen_t optlen)) { struct _rtdm_setsockopt_args args = { level, optname, (void *)optval, optlen }; int ret; ret = do_ioctl(fd, _RTIOC_SETSOCKOPT, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(setsockopt(fd, level, optname, optval, optlen)); } COBALT_IMPL(int, bind, (int fd, const struct sockaddr *my_addr, socklen_t addrlen)) { struct _rtdm_setsockaddr_args args = { my_addr, addrlen }; int ret; ret = do_ioctl(fd, _RTIOC_BIND, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(bind(fd, my_addr, addrlen)); } COBALT_IMPL(int, connect, (int fd, const struct sockaddr *serv_addr, socklen_t addrlen)) { struct _rtdm_setsockaddr_args args = { serv_addr, addrlen }; int ret; ret = do_ioctl(fd, _RTIOC_CONNECT, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(connect(fd, serv_addr, addrlen)); } COBALT_IMPL(int, listen, (int fd, int backlog)) { int ret; ret = do_ioctl(fd, _RTIOC_LISTEN, (void *)(long)backlog); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(listen(fd, backlog)); } COBALT_IMPL(int, accept, (int fd, struct sockaddr *addr, socklen_t *addrlen)) { struct _rtdm_getsockaddr_args args = { addr, addrlen }; int ret; ret = do_ioctl(fd, _RTIOC_ACCEPT, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(accept(fd, addr, addrlen)); } COBALT_IMPL(int, getsockname, (int fd, struct sockaddr *name, socklen_t *namelen)) { struct _rtdm_getsockaddr_args args = { name, namelen }; int ret; ret = do_ioctl(fd, _RTIOC_GETSOCKNAME, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(getsockname(fd, name, namelen)); } COBALT_IMPL(int, getpeername, (int fd, struct sockaddr *name, socklen_t *namelen)) { struct _rtdm_getsockaddr_args args = { name, namelen }; int ret; ret = do_ioctl(fd, _RTIOC_GETPEERNAME, &args); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(getpeername(fd, name, namelen)); } COBALT_IMPL(int, shutdown, (int fd, int how)) { int ret; ret = do_ioctl(fd, _RTIOC_SHUTDOWN, (void *)(long)how); if (ret != -EADV && ret != -ENOSYS) return set_errno(ret); return __STD(shutdown(fd, how)); } COBALT_IMPL(void *, mmap64, (void *addr, size_t length, int prot, int flags, int fd, off64_t offset)) { struct _rtdm_mmap_request rma; int ret; if (fd < 0) /* We don't do anonymous mappings. */ goto regular; /* RTDM ignores the address hint, and rejects MAP_FIXED. */ rma.length = length; rma.offset = offset; rma.prot = prot; rma.flags = flags; ret = XENOMAI_SYSCALL3(sc_cobalt_mmap, fd, &rma, &addr); if (ret != -EADV && ret != -ENOSYS) { ret = set_errno(ret); if (ret) return MAP_FAILED; return addr; } regular: #if mmap64 == mmap return __STD(mmap(addr, length, prot, flags, fd, offset)); #else return __STD(mmap64(addr, length, prot, flags, fd, offset)); #endif } COBALT_IMPL(void *, mmap, (void *addr, size_t length, int prot, int flags, int fd, off_t offset)) { return __COBALT(mmap64(addr, length, prot, flags, fd, offset)); }