diff options
Diffstat (limited to 'rtemsbsd/rtems/rtems-bsd-syscall-api.c')
-rw-r--r-- | rtemsbsd/rtems/rtems-bsd-syscall-api.c | 1533 |
1 files changed, 1521 insertions, 12 deletions
diff --git a/rtemsbsd/rtems/rtems-bsd-syscall-api.c b/rtemsbsd/rtems/rtems-bsd-syscall-api.c index 63274a0e..434cacbd 100644 --- a/rtemsbsd/rtems/rtems-bsd-syscall-api.c +++ b/rtemsbsd/rtems/rtems-bsd-syscall-api.c @@ -1,26 +1,32 @@ -/* - * Copyright (c) 2013 embedded brains GmbH. All rights reserved. +/** + * @file + * + * @ingroup rtems_bsd_rtems * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> + * @brief TODO. + * + * File origin from FreeBSD 'lib/libc/gen/sysctlnametomib.c'. + */ + +/* + * Copyright 2001 The FreeBSD Project. All Rights Reserved. + * Copyright 2020 Chris Johns * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT @@ -29,4 +35,1507 @@ * SUCH DAMAGE. */ +#if !defined(RTEMS_BSD_CHECK_READDIR_DIRENT) +#define RTEMS_BSD_CHECK_READDIR_DIRENT 0 +#endif + +#include <machine/rtems-bsd-kernel-space.h> + +#include <sys/dirent.h> +#include <sys/file.h> +#include <sys/filedesc.h> +#include <sys/proc.h> +#include <sys/syscallsubr.h> +#include <sys/sysproto.h> +#include <sys/vnode.h> + +#include <machine/rtems-bsd-libio.h> #include <machine/rtems-bsd-syscall-api.h> +#include <machine/rtems-bsd-vfs.h> + +#include <errno.h> +#include <rtems/imfs.h> +#include <rtems/libio.h> +#include <rtems/seterr.h> +#include <stdio.h> + +static int rtems_bsd_sysgen_open_error( + rtems_libio_t *iop, const char *path, int oflag, mode_t mode); +static int rtems_bsd_sysgen_open( + rtems_libio_t *iop, const char *path, int oflag, mode_t mode); +static int rtems_bsd_sysgen_close(rtems_libio_t *iop); +static ssize_t rtems_bsd_sysgen_read( + rtems_libio_t *iop, void *buffer, size_t count); +static ssize_t rtems_bsd_sysgen_readv( + rtems_libio_t *iop, const struct iovec *iov, int iovcnt, ssize_t total); +static ssize_t rtems_bsd_sysgen_write( + rtems_libio_t *iop, const void *buffer, size_t count); +static ssize_t rtems_bsd_sysgen_writev( + rtems_libio_t *iop, const struct iovec *iov, int iovcnt, ssize_t total); +static int rtems_bsd_sysgen_ioctl( + rtems_libio_t *iop, ioctl_command_t request, void *buffer); +static off_t rtems_bsd_sysgen_lseek( + rtems_libio_t *iop, off_t offset, int whence); +static int rtems_bsd_sysgen_vnstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf); +static int rtems_bsd_sysgen_fstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf); +static int rtems_bsd_sysgen_imfsfstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf); +static int rtems_bsd_sysgen_ftruncate(rtems_libio_t *iop, off_t length); +static int rtems_bsd_sysgen_fsync(rtems_libio_t *iop); +static int rtems_bsd_sysgen_fdatasync(rtems_libio_t *iop); +static int rtems_bsd_sysgen_fcntl(rtems_libio_t *iop, int cmd); +static int rtems_bsd_sysgen_poll(rtems_libio_t *iop, int events); +static int rtems_bsd_sysgen_kqfilter(rtems_libio_t *iop, struct knote *kn); + +const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_dirops = { + .open_h = rtems_bsd_sysgen_open, + .close_h = rtems_bsd_sysgen_close, + .read_h = rtems_bsd_sysgen_read, + .write_h = rtems_filesystem_default_write, + .ioctl_h = rtems_filesystem_default_ioctl, + .lseek_h = rtems_filesystem_default_lseek_directory, + .fstat_h = rtems_bsd_sysgen_vnstat, + .ftruncate_h = rtems_filesystem_default_ftruncate_directory, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_bsd_sysgen_fdatasync, + .fcntl_h = rtems_filesystem_default_fcntl, + .kqfilter_h = rtems_filesystem_default_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_filesystem_default_poll, + .readv_h = rtems_filesystem_default_readv, + .writev_h = rtems_filesystem_default_writev +}; + +const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_fileops = { + .open_h = rtems_bsd_sysgen_open, + .close_h = rtems_bsd_sysgen_close, + .read_h = rtems_bsd_sysgen_read, + .write_h = rtems_bsd_sysgen_write, + .ioctl_h = rtems_bsd_sysgen_ioctl, + .lseek_h = rtems_bsd_sysgen_lseek, + .fstat_h = rtems_bsd_sysgen_vnstat, + .ftruncate_h = rtems_bsd_sysgen_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_bsd_sysgen_fdatasync, + .fcntl_h = rtems_bsd_sysgen_fcntl, + .kqfilter_h = rtems_bsd_sysgen_kqfilter, + .mmap_h = rtems_filesystem_default_mmap, + .poll_h = rtems_bsd_sysgen_poll, + .readv_h = rtems_bsd_sysgen_readv, + .writev_h = rtems_bsd_sysgen_writev +}; + +const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_nodeops = { + .open_h = rtems_bsd_sysgen_open_error, + .close_h = rtems_bsd_sysgen_close, + .read_h = rtems_bsd_sysgen_read, + .write_h = rtems_bsd_sysgen_write, + .ioctl_h = rtems_bsd_sysgen_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_bsd_sysgen_fstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_bsd_sysgen_fcntl, + .poll_h = rtems_bsd_sysgen_poll, + .kqfilter_h = rtems_bsd_sysgen_kqfilter, + .readv_h = rtems_bsd_sysgen_readv, + .writev_h = rtems_bsd_sysgen_writev, + .mmap_h = rtems_filesystem_default_mmap +}; + +const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_imfsnodeops = { + .open_h = rtems_bsd_sysgen_open_error, + .close_h = rtems_bsd_sysgen_close, + .read_h = rtems_bsd_sysgen_read, + .write_h = rtems_bsd_sysgen_write, + .ioctl_h = rtems_bsd_sysgen_ioctl, + .lseek_h = rtems_filesystem_default_lseek, + .fstat_h = rtems_bsd_sysgen_imfsfstat, + .ftruncate_h = rtems_filesystem_default_ftruncate, + .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, + .fcntl_h = rtems_bsd_sysgen_fcntl, + .poll_h = rtems_bsd_sysgen_poll, + .kqfilter_h = rtems_bsd_sysgen_kqfilter, + .readv_h = rtems_bsd_sysgen_readv, + .writev_h = rtems_bsd_sysgen_writev, + .mmap_h = rtems_filesystem_default_mmap +}; + +int +accept(int socket, struct sockaddr *__restrict address, + socklen_t *__restrict address_len) +{ + struct thread *td; + int error; + struct accept_args ua; + rtems_libio_t *iop; + int afd; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: accept: %d\n", socket); + } + td = rtems_bsd_get_curthread_or_null(); + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + int ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.name = address; + ua.anamelen = address_len; + error = sys_accept(td, &ua); + rtems_bsd_libio_iop_drop(socket); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + iop = rtems_bsd_libio_iop_allocate(); + afd = td->td_retval[0]; + if (iop == NULL) { + kern_close(td, afd); + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, afd, iop, &rtems_bsd_sysgen_nodeops); + if (error != 0) { + rtems_bsd_libio_iop_free(iop); + kern_close(td, afd); + return rtems_bsd_error_to_status_and_errno(error); + } + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: accept: %d (%d) => %d -> %d\n", socket, ffd, + rtems_libio_iop_to_descriptor(iop), + rtems_bsd_libio_iop_to_descriptor(iop)); + } + return rtems_libio_iop_to_descriptor(iop); +} + +int +bind(int socket, const struct sockaddr *address, socklen_t address_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct bind_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: bind: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd == -1) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.name = address; + ua.namelen = address_len; + error = sys_bind(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +connect(int socket, const struct sockaddr *address, socklen_t address_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct connect_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: connect: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.name = address; + ua.namelen = address_len; + error = sys_connect(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +getpeername(int socket, struct sockaddr *__restrict address, + socklen_t *__restrict address_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct getpeername_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: getpeername: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.fdes = ffd; + ua.asa = address; + ua.alen = address_len; + error = sys_getpeername(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +getsockname(int socket, struct sockaddr *__restrict address, + socklen_t *__restrict address_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct getsockname_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: getsockname: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.fdes = ffd; + ua.asa = address; + ua.alen = address_len; + error = sys_getsockname(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +getsockopt(int socket, int level, int option_name, + void *__restrict option_value, socklen_t *__restrict option_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct getsockopt_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: getsockopt: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.level = level; + ua.name = option_name; + ua.val = (caddr_t)option_value; + ua.avalsize = option_len; + error = sys_getsockopt(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +kqueue(void) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct kqueue_args ua = {}; + rtems_libio_t *iop; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: kqueue:\n"); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + iop = rtems_bsd_libio_iop_allocate(); + if (iop == NULL) { + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + error = sys_kqueue(td, &ua); + if (error != 0) { + goto out; + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, td->td_retval[0], iop, &rtems_bsd_sysgen_nodeops); + if (error == 0) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: kqueue: %d -> %d\n", + rtems_libio_iop_to_descriptor(iop), + rtems_bsd_libio_iop_to_descriptor(iop)); + } + return rtems_libio_iop_to_descriptor(iop); + } + kern_close(td, rtems_libio_iop_to_descriptor(iop)); +out: + rtems_bsd_libio_iop_free(iop); + return rtems_bsd_error_to_status_and_errno(error); +} + +__weak_reference(kevent, _kevent); + +int +kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct kevent_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: kevent: %d\n", kq); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(kq, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.fd = ffd; + ua.changelist = changelist; + ua.nchanges = nchanges; + ua.eventlist = eventlist; + ua.nevents = nevents; + ua.timeout = timeout; + error = sys_kevent(td, &ua); + rtems_bsd_libio_iop_drop(kq); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +int +listen(int socket, int backlog) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct listen_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: listen: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.backlog = backlog; + error = sys_listen(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +pipe(int fildes[2]) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + rtems_libio_t *iop[2]; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: pipe: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + iop[0] = rtems_bsd_libio_iop_allocate(); + if (iop[0] == NULL) { + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + iop[1] = rtems_bsd_libio_iop_allocate(); + if (iop[1] == NULL) { + rtems_bsd_libio_iop_free(iop[0]); + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + error = kern_pipe(td, fildes, 0, NULL, NULL); + if (error != 0) { + goto out; + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, fildes[0], iop[0], &rtems_bsd_sysgen_nodeops); + if (error != 0) { + goto out; + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, fildes[1], iop[1], &rtems_bsd_sysgen_nodeops); + if (error == 0) { + fildes[0] = rtems_libio_iop_to_descriptor(iop[0]); + fildes[1] = rtems_libio_iop_to_descriptor(iop[1]); + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: pipe: %d -> %d, %d -> %d\n", + fildes[0], + rtems_bsd_libio_iop_to_descriptor(iop[0]), + fildes[1], + rtems_bsd_libio_iop_to_descriptor(iop[1])); + } + return 0; + } +out: + kern_close(td, rtems_bsd_libio_iop_to_descriptor(iop[0])); + kern_close(td, rtems_bsd_libio_iop_to_descriptor(iop[1])); + rtems_bsd_libio_iop_free(iop[0]); + rtems_bsd_libio_iop_free(iop[1]); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +poll(struct pollfd fds[], nfds_t nfds, int timeout) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct poll_args ua; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: poll: %d\n", nfds); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + /* + * Pass libio descriptors through as libio and bsd descriptors + * can be in the list at the same time. + */ + ua.fds = &fds[0]; + ua.nfds = nfds; + ua.timeout = timeout; + error = sys_poll(td, &ua); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +int +pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, + const struct timespec *timeout, const sigset_t *set) +{ + struct thread *td; + struct timeval tv; + struct timeval *tvp; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: pselect: %d\n", nfds); + } + if (set != NULL) { + return rtems_bsd_error_to_status_and_errno(ENOSYS); + } + td = rtems_bsd_get_curthread_or_null(); + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + if (timeout != NULL) { + TIMESPEC_TO_TIMEVAL(&tv, timeout); + tvp = &tv; + } else { + tvp = NULL; + } + /* + * Pass libio descriptors through as libio and bsd descriptors + * can be in the list at the same time. + */ + error = kern_select( + td, nfds, readfds, writefds, errorfds, tvp, NFDBITS); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +ssize_t +recvfrom(int socket, void *__restrict buffer, size_t length, int flags, + struct sockaddr *__restrict address, socklen_t *__restrict address_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct recvfrom_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: recvfrom: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.buf = buffer; + ua.len = length; + ua.flags = flags; + ua.from = address; + ua.fromlenaddr = address_len; + error = sys_recvfrom(td, &ua); + rtems_bsd_libio_iop_drop(socket); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +ssize_t +recvmsg(int socket, struct msghdr *message, int flags) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct recvmsg_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: recvmsg: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.msg = message; + ua.flags = flags; + error = sys_recvmsg(td, &ua); + rtems_bsd_libio_iop_drop(socket); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +int +select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errorfds, + struct timeval *timeout) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: select: %d\n", nfds); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + /* + * Pass libio descriptors through as libio and bsd descriptors + * can be in the list at the same time. + */ + error = kern_select( + td, nfds, readfds, writefds, errorfds, timeout, NFDBITS); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +ssize_t +sendto(int socket, const void *message, size_t length, int flags, + const struct sockaddr *dest_addr, socklen_t dest_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct sendto_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: sendto: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.buf = (caddr_t)message; + ua.len = length; + ua.flags = flags; + ua.to = dest_addr; + ua.tolen = dest_len; + error = sys_sendto(td, &ua); + rtems_bsd_libio_iop_drop(socket); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_retval[0]; +} + +ssize_t +sendmsg(int socket, const struct msghdr *message, int flags) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct sendmsg_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: sendmsg: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.msg = message; + ua.flags = flags; + error = sys_sendmsg(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +setfib(int fibnum) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + int error; + if (td != NULL) { + struct setfib_args ua = { .fibnum = fibnum }; + error = sys_setfib(td, &ua); + } else { + error = ENOMEM; + } + return rtems_bsd_error_to_status_and_errno(error); +} + +int +setsockopt(int socket, int level, int option_name, const void *option_value, + socklen_t option_len) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct setsockopt_args ua; + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: setsockopt: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + ua.s = ffd; + ua.level = level; + ua.name = option_name; + ua.val = __DECONST(void *, option_value); + ua.valsize = option_len; + error = sys_setsockopt(td, &ua); + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +shutdown(int socket, int how) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + int ffd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: shutdown: %d\n", socket); + } + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + ffd = rtems_bsd_libio_iop_hold(socket, NULL); + if (ffd < 0) { + return rtems_bsd_error_to_status_and_errno(EBADF); + } + if (rtems_bsd_is_libbsd_descriptor(rtems_libio_iop(socket))) { + struct shutdown_args ua = { .s = ffd, .how = how }; + error = sys_shutdown(td, &ua); + } else { + error = ENOTSOCK; + } + rtems_bsd_libio_iop_drop(socket); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +socket(int domain, int type, int protocol) +{ + struct thread *td; + rtems_libio_t *iop; + struct socket_args ua; + int error; + td = rtems_bsd_get_curthread_or_null(); + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + iop = rtems_bsd_libio_iop_allocate(); + if (iop == NULL) { + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + ua.domain = domain; + ua.type = type; + ua.protocol = protocol; + error = sys_socket(td, &ua); + if (error != 0) { + rtems_bsd_libio_iop_free(iop); + return rtems_bsd_error_to_status_and_errno(error); + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, td->td_retval[0], iop, &rtems_bsd_sysgen_nodeops); + if (error != 0) { + kern_close(td, td->td_retval[0]); + rtems_bsd_libio_iop_free(iop); + return rtems_bsd_error_to_status_and_errno(error); + } + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: socket: %d -> %d\n", + rtems_libio_iop_to_descriptor(iop), + rtems_bsd_libio_iop_to_descriptor(iop)); + } + return rtems_libio_iop_to_descriptor(iop); +} + +int +socketpair(int domain, int type, int protocol, int *socket_vector) +{ + struct thread *td; + rtems_libio_t *iop[2]; + struct socketpair_args ua; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: socketpair:\n"); + } + td = rtems_bsd_get_curthread_or_null(); + if (td == NULL) { + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + iop[0] = rtems_bsd_libio_iop_allocate(); + if (iop[0] == NULL) { + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + iop[1] = rtems_bsd_libio_iop_allocate(); + if (iop[1] == NULL) { + rtems_bsd_libio_iop_free(iop[0]); + return rtems_bsd_error_to_status_and_errno(ENFILE); + } + ua.domain = domain; + ua.type = type; + ua.protocol = protocol; + ua.rsv = socket_vector; + error = sys_socketpair(td, &ua); + if (error != 0) { + goto out; + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, socket_vector[0], iop[0], &rtems_bsd_sysgen_nodeops); + if (error != 0) { + goto out; + } + error = rtems_bsd_libio_iop_set_bsd_fd( + td, socket_vector[1], iop[1], &rtems_bsd_sysgen_nodeops); + if (error == 0) { + socket_vector[0] = rtems_libio_iop_to_descriptor(iop[0]); + socket_vector[1] = rtems_libio_iop_to_descriptor(iop[1]); + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: socketpair: %d -> %d, %d -> %d\n", + socket_vector[0], + rtems_bsd_libio_iop_to_descriptor(iop[0]), + socket_vector[1], + rtems_bsd_libio_iop_to_descriptor(iop[1])); + } + return 0; + } +out: + kern_close(td, rtems_bsd_libio_iop_to_descriptor(iop[0])); + kern_close(td, rtems_bsd_libio_iop_to_descriptor(iop[1])); + rtems_bsd_libio_iop_free(iop[0]); + rtems_bsd_libio_iop_free(iop[1]); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) +{ + int error = EINVAL; + if (namelen <= CTL_MAXNAME) { + int namedup[CTL_MAXNAME]; + memcpy(namedup, name, namelen * sizeof(*name)); + error = kernel_sysctl(NULL, namedup, namelen, oldp, oldlenp, + RTEMS_DECONST(void *, newp), newlen, oldlenp, 0); + } + return rtems_bsd_error_to_status_and_errno(error); +} + +/* + * File origin from FreeBSD 'lib/libc/gen/sysctlbyname.c'. + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + */ +int +sysctlbyname(const char *name, void *oldp, size_t *oldlenp, const void *newp, + size_t newlen) +{ + int real_oid[CTL_MAXNAME + 2]; + int error; + size_t oidlen; + oidlen = sizeof(real_oid) / sizeof(int); + error = sysctlnametomib(name, real_oid, &oidlen); + if (error < 0) + return (error); + error = sysctl(real_oid, oidlen, oldp, oldlenp, newp, newlen); + return rtems_bsd_error_to_status_and_errno(error); +} + +/* + * File origin from FreeBSD 'lib/libc/gen/sysctlnametomib.c'. + * + * This function uses a presently undocumented interface to the kernel + * to walk the tree and get the type so it can print the value. + * This interface is under work and consideration, and should probably + * be killed with a big axe by the first person who can find the time. + * (be aware though, that the proper interface isn't as obvious as it + * may seem, there are various conflicting requirements. + */ +int +sysctlnametomib(const char *name, int *mibp, size_t *sizep) +{ + int oid[2]; + int error; + oid[0] = 0; + oid[1] = 3; + *sizep *= sizeof(int); + error = sysctl(oid, 2, mibp, sizep, name, strlen(name)); + *sizep /= sizeof(int); + return (error); +} + +static int +rtems_bsd_sysgen_open_error( + rtems_libio_t *iop, const char *path, int oflag, mode_t mode) +{ + return rtems_bsd_error_to_status_and_errno(ENXIO); +} + +int +rtems_bsd_sysgen_open( + rtems_libio_t *iop, const char *path, int oflag, mode_t mode) +{ + struct thread *td = rtems_bsd_get_curthread_or_null(); + struct filedesc *fdp; + struct file *fp; + const bool creat = (oflag & O_CREAT) == O_CREAT; + struct vnode *cdir; + struct vnode *rdir; + const char *opath; + int opathlen; + int fd; + int error; + + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: open: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + + fdp = td->td_proc->p_fd; + + /* + * There is no easy or clean means to open a vnode and follow the + * POSIX open semantics. You can open a vnode but the extra + * functionality such as create and truncate are not part of the + * basic vnode open. All the calls that provide that functionality + * take a path as the argument. As a result find the last token in + * the path and use the parent directory vnode to position ourselves + * in the parent directory. The pathloc vnode points to the '.' or + * '..' directory. + */ + opath = path + strlen(path); + opathlen = 0; + while (opath != path && !rtems_filesystem_is_delimiter(opath[-1])) { + opath--; + opathlen++; + } + if (rtems_filesystem_is_current_directory(opath, opathlen) || + rtems_filesystem_is_parent_directory(opath, opathlen)) { + if (((oflag + 1) & _FWRITE) == _FWRITE) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: open: write to . or ..\n"); + } + return rtems_bsd_error_to_status_and_errno(EPERM); + } + opath = "."; + cdir = rtems_bsd_libio_loc_to_vnode(&iop->pathinfo); + } else { + rtems_filesystem_location_info_t *rootloc = + &iop->pathinfo.mt_entry->mt_fs_root->location; + cdir = rtems_bsd_libio_loc_to_vnode_dir(&iop->pathinfo); + if (fdp->fd_cdir == NULL || + rtems_bsd_libio_loc_to_vnode(&iop->pathinfo) == + rtems_bsd_libio_loc_to_vnode(rootloc)) { + cdir = rtems_bsd_libio_loc_to_vnode(rootloc); + } + } + + FILEDESC_XLOCK(fdp); + rdir = fdp->fd_cdir; + fdp->fd_cdir = cdir; + cdir = rdir; + rdir = fdp->fd_rdir; + fdp->fd_rdir = fdp->fd_cdir; + FILEDESC_XUNLOCK(fdp); + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: open: path=%s opath=%s vn=%p cwd=%p" + " flags=%08x mode=%08x\n", + path, opath, + creat ? NULL : rtems_bsd_libio_loc_to_vnode(&iop->pathinfo), + fdp->fd_cdir, oflag, mode); + } + + VREF(fdp->fd_cdir); + + error = kern_openat(td, AT_FDCWD, RTEMS_DECONST(char *, opath), + UIO_USERSPACE, oflag, mode); + + vrele(fdp->fd_cdir); + + if (error != 0) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: open: error = (%d) %s\n", error, + strerror(error)); + } + return rtems_bsd_error_to_status_and_errno(error); + } + + fd = td->td_retval[0]; + + FILEDESC_XLOCK(fdp); + fdp->fd_cdir = cdir; + fdp->fd_rdir = rdir; + if (fd < fdp->fd_nfiles) { + struct vnode *vn; + fp = fget_locked(fdp, fd); + if (fp != NULL) { + vn = fp->f_vnode; + } else { + vn = NULL; + } + rtems_bsd_libio_loc_set_vnode(&iop->pathinfo, vn); + } + FILEDESC_XUNLOCK(fdp); + + rtems_bsd_libio_iop_set_bsd_fd(td, fd, iop, &rtems_bsd_sysgen_fileops); + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: open: fd = %d vn=%p\n", fd, + rtems_bsd_libio_loc_to_vnode(&iop->pathinfo)); + } + + return 0; +} + +int +rtems_bsd_sysgen_close(rtems_libio_t *iop) +{ + struct thread *td = curthread; + int error; + int ffd = rtems_bsd_libio_iop_to_descriptor(iop); + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: close: %d -> %d\n", + rtems_libio_iop_to_descriptor(iop), ffd); + } + if (td != NULL) { + if (ffd >= 0) { + rtems_libio_iop_hold(iop); + error = kern_close(td, ffd); + } else { + error = EBADF; + } + } else { + error = ENOMEM; + } + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: close: %d: %d: %s\n", + rtems_libio_iop_to_descriptor(iop), error, strerror(error)); + } + return rtems_bsd_error_to_status_and_errno(error); +} + +ssize_t +rtems_bsd_sysgen_read(rtems_libio_t *iop, void *buffer, size_t count) +{ + struct thread *td = curthread; + struct vnode *vp = rtems_bsd_libio_iop_to_vnode(iop); + int fd = rtems_bsd_libio_iop_to_descriptor(iop); + int error; + ssize_t size = 0; + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: read: %d -> %d: vn=%p len=%d\n", + rtems_libio_iop_to_descriptor(iop), fd, vp, count); + } + + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: read: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + + if (count > IOSIZE_MAX) + return rtems_bsd_error_to_status_and_errno(EINVAL); + + if (vp != NULL && vp->v_type == VDIR) { + off_t offset; + error = kern_getdirentries( + td, fd, buffer, count, &iop->offset, NULL, UIO_USERSPACE); + size = td->td_retval[0]; + if (RTEMS_BSD_CHECK_READDIR_DIRENT) { + /* + * Helper code for integration of a file system. The + * FreeBSD kernel dirent and the newlib structs are not + * the same format. + */ + size_t offset = 0; + int c = 0; + printk( + "bsd: sys: readdir: buffer: %p count:%d: size=%d\n", + buffer, count, size); + while (offset < size) { + struct dirent *dp = + (struct dirent *)(((char *)buffer) + + offset); + printk( + "dirent: %3d: dp=%p off=%d rl=%-3d fn=%-6d name=%-3d '", + c, dp, (int)dp->d_off, (int)dp->d_reclen, + (int)dp->d_fileno, (int)dp->d_namlen); + if (dp->d_namlen < sizeof(dp->d_name)) { + for (int i = 0; i < dp->d_namlen; ++i) { + printk("%c", dp->d_name[i]); + } + } else { + printk("INVALID NAME LENGTH"); + } + printk("'\n"); + if (dp->d_reclen <= 0) { + break; + } + c++; + offset += dp->d_reclen; + if (offset > count) { + printf("dirent: buffer overflow\n"); + } + } + } + } else { + struct iovec aiov = { .iov_base = buffer, .iov_len = count }; + struct uio auio = { .uio_iov = &aiov, + .uio_iovcnt = 1, + .uio_offset = iop->offset, + .uio_resid = count, + .uio_segflg = UIO_USERSPACE, + .uio_rw = UIO_READ, + .uio_td = td }; + error = kern_readv( + td, rtems_bsd_libio_iop_to_descriptor(iop), &auio); + if (error == 0) + size = td->td_retval[0]; + } + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: read: %d: %d: %s size=%i\n", + rtems_libio_iop_to_descriptor(iop), error, strerror(error), + size); + } + + if (error != 0) + return rtems_bsd_error_to_status_and_errno(error); + + return size; +} + +ssize_t +rtems_bsd_sysgen_readv( + rtems_libio_t *iop, const struct iovec *iov, int iovcnt, ssize_t total) +{ + struct thread *td = curthread; + struct uio auio; + int error; + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: readv: %d len=%d\n", + rtems_libio_iop_to_descriptor(iop), total); + } + + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: readv: readv: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + + if (total > IOSIZE_MAX) + return rtems_bsd_error_to_status_and_errno(EINVAL); + + auio.uio_iov = RTEMS_DECONST(struct iovec *, iov); + auio.uio_iovcnt = iovcnt; + auio.uio_resid = total; + auio.uio_segflg = UIO_USERSPACE; + + error = kern_readv(td, rtems_bsd_libio_iop_to_descriptor(iop), &auio); + + if (error != 0) + return rtems_bsd_error_to_status_and_errno(error); + + return td->td_retval[0]; +} + +ssize_t +rtems_bsd_sysgen_write(rtems_libio_t *iop, const void *buffer, size_t count) +{ + struct thread *td = curthread; + struct uio auio; + struct iovec aiov; + int error; + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: write: %d len=%d\n", + rtems_libio_iop_to_descriptor(iop), count); + } + + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: write: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + + if (count > IOSIZE_MAX) + return (EINVAL); + + aiov.iov_base = RTEMS_DECONST(void *, buffer); + aiov.iov_len = count; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = count; + auio.uio_segflg = UIO_USERSPACE; + + error = kern_writev(td, rtems_bsd_libio_iop_to_descriptor(iop), &auio); + + if (error != 0) + return rtems_bsd_error_to_status_and_errno(error); + + return td->td_retval[0]; +} + +ssize_t +rtems_bsd_sysgen_writev( + rtems_libio_t *iop, const struct iovec *iov, int iovcnt, ssize_t total) +{ + struct thread *td = curthread; + struct uio auio; + int error; + + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: writev: %d iocnt=%d len=%d\n", + rtems_libio_iop_to_descriptor(iop), iovcnt, total); + } + + if (total > IOSIZE_MAX) + return EINVAL; + + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: writev: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + + auio.uio_iov = RTEMS_DECONST(struct iovec *, iov); + auio.uio_iovcnt = iovcnt; + auio.uio_resid = total; + auio.uio_segflg = UIO_USERSPACE; + + error = kern_writev(td, rtems_bsd_libio_iop_to_descriptor(iop), &auio); + + if (error != 0) + return rtems_bsd_error_to_status_and_errno(error); + + return td->td_retval[0]; +} + +int +rtems_bsd_sysgen_ioctl( + rtems_libio_t *iop, ioctl_command_t request, void *buffer) +{ + struct thread *td = curthread; + u_long com = request & 0xffffffff; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: ioctl: %d req=%08x\n", + rtems_libio_iop_to_descriptor(iop), com); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: ioctl: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + error = kern_ioctl( + td, rtems_bsd_libio_iop_to_descriptor(iop), com, buffer); + return rtems_bsd_error_to_status_and_errno(error); +} + +off_t +rtems_bsd_sysgen_lseek(rtems_libio_t *iop, off_t offset, int whence) +{ + struct thread *td = curthread; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: lseek: %d offset=%zu whence=%d\n", + rtems_libio_iop_to_descriptor(iop), offset, whence); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: lseek: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + error = kern_lseek( + td, rtems_bsd_libio_iop_to_descriptor(iop), offset, whence); + if (error != 0) { + return rtems_bsd_error_to_status_and_errno(error); + } + return td->td_uretoff.tdu_off; +} + +int +rtems_bsd_sysgen_vnstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf) +{ + struct thread *td = curthread; + struct vnode *vp = rtems_bsd_libio_loc_to_vnode(loc); + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: vnstat: %p\n", vp); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: vnstat: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + if (vp == NULL) + error = EFAULT; + else { + VOP_LOCK(vp, LK_SHARED); + error = vn_stat(vp, buf, td->td_ucred, NOCRED, td); + VOP_UNLOCK(vp, 0); + } + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: vnstat: exit %p\n", vp); + } + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_fstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf) +{ + struct thread *td = curthread; + rtems_libio_t *iop = rtems_bsd_libio_loc_to_iop(loc); + struct filedesc *fdp; + struct file *fp = NULL; + int fd; + int error; + if (iop == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: ffile: no iop\n"); + } + return rtems_bsd_error_to_status_and_errno(ENXIO); + } + fd = rtems_bsd_libio_iop_to_descriptor(iop); + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fstat: %d\n", fd); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fstat: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + if (fd < fdp->fd_nfiles) { + fp = fget_locked(fdp, fd); + } + FILEDESC_XUNLOCK(fdp); + if (fp != NULL) { + error = fo_stat(fp, buf, NULL, td); + } else { + error = EBADF; + } + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_imfsfstat( + const rtems_filesystem_location_info_t *loc, struct stat *buf) +{ + struct thread *td = curthread; + struct socket *so = rtems_bsd_libio_imfs_loc_to_so(loc); + struct filedesc *fdp; + struct file *fp = NULL; + struct socket *fd_so = NULL; + int fd; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: imfsfstat: socket=%p\n", so); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fstat: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + fdp = td->td_proc->p_fd; + FILEDESC_XLOCK(fdp); + for (fd = 0; fd < fdp->fd_nfiles; fd++) { + fp = fget_locked(fdp, fd); + fd_so = fp->f_data; + if (so == fd_so) { + break; + } + fp = NULL; + } + FILEDESC_XUNLOCK(fdp); + if (fp != NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: imfsfstat: %d\n", fd); + } + error = fo_stat(fp, buf, NULL, td); + } else { + error = EBADF; + } + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_ftruncate(rtems_libio_t *iop, off_t length) +{ + struct thread *td = curthread; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: ftruncate: len=%d\n", length); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: ftruncate: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + error = kern_ftruncate( + td, rtems_bsd_libio_iop_to_descriptor(iop), length); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_fsync(rtems_libio_t *iop) +{ + struct thread *td = curthread; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fsync\n"); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fsync: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + error = kern_fsync(td, rtems_bsd_libio_iop_to_descriptor(iop), true); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_fdatasync(rtems_libio_t *iop) +{ + struct thread *td = curthread; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fdatasync\n"); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fdatasync: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + error = kern_fsync(td, rtems_bsd_libio_iop_to_descriptor(iop), false); + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_fcntl(rtems_libio_t *iop, int cmd) +{ + struct thread *td = curthread; + intptr_t arg; + int error; + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fcntl: %d cmd=%d\n", + rtems_libio_iop_to_descriptor(iop), cmd); + } + if (td == NULL) { + if (RTEMS_BSD_SYSCALL_TRACE) { + printf("bsd: sys: fcntl: no curthread\n"); + } + return rtems_bsd_error_to_status_and_errno(ENOMEM); + } + switch (cmd) { + case F_SETFD: + arg = rtems_libio_to_fcntl_flags(rtems_libio_iop_flags(iop)) & + FD_CLOEXEC; + break; + case F_SETFL: + arg = rtems_libio_to_fcntl_flags(rtems_libio_iop_flags(iop)) & + FCNTLFLAGS; + break; + default: + arg = -1; + error = 0; + break; + } + if (arg >= 0) { + error = kern_fcntl( + td, rtems_bsd_libio_iop_to_descriptor(iop), cmd, arg); + /* no return path with the RTEMS API for get calls */ + } + return rtems_bsd_error_to_status_and_errno(error); +} + +int +rtems_bsd_sysgen_poll(rtems_libio_t *iop, int events) +{ + printf("rtems_bsd_sysgen_poll called!\n"); + return rtems_bsd_error_to_status_and_errno(EOPNOTSUPP); +} + +int +rtems_bsd_sysgen_kqfilter(rtems_libio_t *iop, struct knote *kn) +{ + printf("rtems_bsd_sysgen_kqfilter called!\n"); + return rtems_bsd_error_to_status_and_errno(EOPNOTSUPP); +} |