rtems-libbsd/rtemsbsd/include/machine/rtems-bsd-libio.h
Kinsey Moore f0fe0439c4 rtemsbsd/libio: Handle invalid descriptors
The documentation for this function suggests that it can handle invalid
descriptors safely. This change allows negative descriptors to be
handled without a crash.
2023-09-20 15:50:25 -05:00

333 lines
8.4 KiB
C

/**
* @file
*
* @ingroup rtems_bsd_machine
*
* @brief LibIO interface for FreeBSD filedesc.
*/
/*
* Copyright (c) 2020 Chrs Johns. All rights reserved.
*
* 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
* 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
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _RTEMS_BSD_MACHINE_RTEMS_BSD_LIBIO_H_
#define _RTEMS_BSD_MACHINE_RTEMS_BSD_LIBIO_H_
#include <sys/event.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <machine/rtems-bsd-vfs.h>
#include <rtems/libio.h>
#include <rtems/libio_.h>
#include <rtems/seterr.h>
#include <stdint.h>
struct rtems_bsd_vfs_loc;
extern const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_nodeops;
extern const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_imfsnodeops;
extern const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_dirops;
extern const rtems_filesystem_file_handlers_r rtems_bsd_sysgen_fileops;
static int inline rtems_bsd_error_to_status_and_errno(int error)
{
if (error == 0) {
return 0;
} else {
rtems_set_errno_and_return_minus_one(error);
}
}
static inline uint32_t
rtems_bsd_libio_fflag_to_flags(u_int fflag)
{
uint32_t libio_flags = 0;
if ((fflag & FREAD) == FREAD) {
libio_flags |= LIBIO_FLAGS_READ;
}
if ((fflag & FWRITE) == FWRITE) {
libio_flags |= LIBIO_FLAGS_WRITE;
}
if ((fflag & FNONBLOCK) == FNONBLOCK) {
libio_flags |= LIBIO_FLAGS_NO_DELAY;
}
return (libio_flags);
}
static inline u_int
rtems_bsd_libio_flags_to_fflag(uint32_t libio_flags)
{
u_int fflag = 0;
if ((libio_flags & LIBIO_FLAGS_READ) == LIBIO_FLAGS_READ) {
fflag |= FREAD;
}
if ((libio_flags & LIBIO_FLAGS_WRITE) == LIBIO_FLAGS_WRITE) {
fflag |= FWRITE;
}
if ((libio_flags & LIBIO_FLAGS_NO_DELAY) == LIBIO_FLAGS_NO_DELAY) {
fflag |= FNONBLOCK;
}
return (fflag);
}
static inline bool
rtems_bsd_is_libbsd_nvops(rtems_libio_t *iop)
{
return (iop->pathinfo.handlers == &rtems_bsd_sysgen_dirops ||
iop->pathinfo.handlers == &rtems_bsd_sysgen_fileops);
}
static inline bool
rtems_bsd_is_libbsd_descriptor(rtems_libio_t *iop)
{
return (iop->pathinfo.handlers == &rtems_bsd_sysgen_nodeops ||
rtems_bsd_is_libbsd_nvops(iop));
}
static inline rtems_libio_t *
rtems_bsd_libio_loc_to_iop(const rtems_filesystem_location_info_t *loc)
{
return (rtems_libio_t *)RTEMS_DECONST(
rtems_filesystem_location_info_t *, loc)
->node_access;
}
struct socket;
static inline struct socket *
rtems_bsd_libio_imfs_loc_to_so(const rtems_filesystem_location_info_t *loc)
{
return (struct socket *)RTEMS_DECONST(
rtems_filesystem_location_info_t *, loc)
->node_access_2;
}
static struct vnode *
rtems_bsd_libio_loc_to_vnode(const rtems_filesystem_location_info_t *loc)
{
return (struct vnode *)RTEMS_DECONST(
rtems_filesystem_location_info_t *, loc)
->node_access;
}
static struct vnode *
rtems_bsd_libio_loc_to_vnode_dir(const rtems_filesystem_location_info_t *loc)
{
return (struct vnode *)RTEMS_DECONST(
rtems_filesystem_location_info_t *, loc)
->node_access_2;
}
static inline void
rtems_bsd_libio_iop_free(rtems_libio_t *iop)
{
rtems_libio_free(iop);
}
static int
rtems_bsd_libio_iop_to_descriptor(rtems_libio_t *iop)
{
return (int)iop->data0;
}
static struct vnode *
rtems_bsd_libio_iop_to_vnode(rtems_libio_t *iop)
{
return rtems_bsd_libio_loc_to_vnode(&iop->pathinfo);
}
static int
rtems_bsd_libio_fd_to_descriptor(int fd)
{
return rtems_bsd_libio_iop_to_descriptor(rtems_libio_iop(fd));
}
static inline struct file *
rtems_bsd_libio_iop_to_file_hold(rtems_libio_t *iop, struct thread *td)
{
struct file *fp;
int error = fget_unlocked(td->td_proc->p_fd,
rtems_bsd_libio_iop_to_descriptor(iop), NULL, &fp, NULL);
if (error != 0) {
fp = NULL;
}
return fp;
}
static inline int
rtems_bsd_file_to_libio_fd(struct file *fp)
{
return fp->f_io - rtems_libio_iops;
}
static inline void
rtems_bsd_libio_iop_set_bsd_descriptor(rtems_libio_t *iop, int fd)
{
iop->data0 = fd;
/* if not vnops the fstat passes a loc, need to get the iop to get the
* fp */
if (!rtems_bsd_is_libbsd_nvops(iop)) {
iop->pathinfo.node_access = iop;
}
}
static inline void
rtems_bsd_libio_iop_set_bsd_file(rtems_libio_t *iop, struct file *fp)
{
fp->f_io = iop;
}
/*
* The fd is a libio file descriptor.
*
* Return -1 if the descriptor is closed or not valid. The descriptor is not
* held.
*
* If open hold the descriptor. If the descriptor referneces a BSD
* descriptor return the BSD descriptor else return the libio descriptor.
*
* Optionally return the iop in *iopp if the descriptor if a libio descriptor
* else return NULL.
*/
static inline int
rtems_bsd_libio_iop_hold(int fd, rtems_libio_t **iopp)
{
rtems_libio_t *iop = NULL;
unsigned int flags = 0;
int ffd = -1;
if (fd >= 0 && fd < rtems_libio_number_iops) {
iop = rtems_libio_iop(fd);
flags = rtems_libio_iop_hold(iop);
if ((flags & LIBIO_FLAGS_OPEN) != 0) {
if (rtems_bsd_is_libbsd_descriptor(iop)) {
ffd = rtems_bsd_libio_iop_to_descriptor(iop);
if (iopp != NULL) {
*iopp = NULL;
}
} else {
ffd = fd;
if (iopp != NULL) {
*iopp = iop;
}
}
} else {
rtems_libio_iop_drop(iop);
}
if (RTEMS_BSD_DESCRIP_TRACE)
flags = iop->flags;
} else {
if (iopp != NULL) {
*iopp = NULL;
}
}
if (RTEMS_BSD_DESCRIP_TRACE)
printf("bsd: iop: hold: fd=%d ffd=%d refs=%d iop=%p by %p\n",
fd, ffd, flags >> 12, iop, __builtin_return_address(0));
return ffd;
}
static inline int
rtems_bsd_libio_iop_drop(int fd)
{
if (RTEMS_BSD_DESCRIP_TRACE)
printf("bsd: iop: drop: fd=%d refs=%d by %p\n", fd,
rtems_libio_iop(fd)->flags >> 12,
__builtin_return_address(0));
rtems_libio_iop_drop(rtems_libio_iop(fd));
return 0;
}
static inline int
rtems_bsd_libio_fo_poll(int fd, struct file *fp, int events,
struct ucred *active_cred, struct thread *td)
{
int error;
if (fp == NULL) {
rtems_libio_t *iop = rtems_libio_iop(fd);
error = (*iop->pathinfo.handlers->poll_h)(iop, events);
} else {
error = (*fp->f_ops->fo_poll)(fp, events, active_cred, td);
fd = rtems_bsd_file_to_libio_fd(fp);
}
rtems_bsd_libio_iop_drop(fd);
return error;
}
static inline void
rtems_bsd_libio_iop_to_knote(struct knote *kn, rtems_libio_t *iop)
{
kn->kn_fp = (struct file *)iop;
}
static inline struct kqueue *
rtems_bsd_libio_knote_to_kq(struct knote *kn)
{
struct kqueue *kq = kn->kn_kq;
if ((kn->kn_status & KN_FP_IS_IOP) == 0) {
if (kq != kn->kn_fp->f_data)
panic("libio kq wrong\n");
}
return kq;
}
/*
* Returns an iop with null file system mount or NULL is ENFILE.
*/
rtems_libio_t *rtems_bsd_libio_iop_allocate(void);
/*
* Returns the libio descriptor or -1 if ENFILE.
*/
int rtems_bsd_libio_iop_allocate_with_file(
struct thread *td, int fd, const rtems_filesystem_file_handlers_r *ops);
/*
* Set the BSD file descriptor in the iop. Returns 0 if successful or an error
* number,
*/
int rtems_bsd_libio_iop_set_bsd_fd(struct thread *td, int fd,
rtems_libio_t *iop, const rtems_filesystem_file_handlers_r *ops);
/*
* Set the vnode in the libio location.
*/
void rtems_bsd_libio_loc_set_vnode(
rtems_filesystem_location_info_t *loc, struct vnode *vn);
void rtems_bsd_libio_loc_set_vnode_dir(
rtems_filesystem_location_info_t *loc, struct vnode *dvn);
#endif /* _RTEMS_BSD_MACHINE_RTEMS_BSD_LIBIO_H_ */