/* $NetBSD: shmif_user.c,v 1.5 2019/03/26 08:56:17 bad Exp $ */
/*-
* Copyright (c) 2009, 2010 Antti Kantee. 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 ``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.
*/
#include <sys/cdefs.h>
#ifdef __KERNEL_RCSID
__KERNEL_RCSID(0, "$NetBSD: shmif_user.c,v 1.5 2019/03/26 08:56:17 bad Exp $");
#endif
#ifndef _KERNEL
#include <sys/types.h>
#include <sys/mman.h>
#include <errno.h>
#include <unistd.h>
#include <rump/rumpuser_component.h>
#include "shmif_user.h"
#define seterr(_v_) if ((_v_) == -1) *error = errno; else *error = 0;
/*
* On BSD we use kqueue, on Linux we use inotify. The underlying
* interface requirements aren't quite the same, but we have a very
* good chance of doing the fd->path mapping on Linux thanks to dcache,
* so just keep the existing interfaces for now.
*/
#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) \
|| defined(__OpenBSD__)
#include <sys/event.h>
#include <stdlib.h>
int
rumpcomp_shmif_watchsetup(int *kqp, int fd)
{
struct kevent kev;
int rv, kq;
kq = *kqp;
if (kq == -1) {
kq = kqueue();
if (kq == -1) {
rv = errno;
goto out;
}
}
EV_SET(&kev, fd, EVFILT_VNODE, EV_ADD|EV_ENABLE|EV_CLEAR,
NOTE_WRITE, 0, 0);
if (kevent(kq, &kev, 1, NULL, 0, NULL) == -1) {
rv = errno;
} else {
rv = 0;
*kqp = kq;
}
out:
return rumpuser_component_errtrans(rv);
}
int
rumpcomp_shmif_watchwait(int kq)
{
void *cookie;
struct kevent kev;
int rv;
cookie = rumpuser_component_unschedule();
do {
rv = kevent(kq, NULL, 0, &kev, 1, NULL);
} while (rv == -1 && errno == EINTR);
if (rv == -1) {
rv = errno;
} else {
rv = 0;
}
rumpuser_component_schedule(cookie);
return rumpuser_component_errtrans(rv);
}
#elif defined(__linux__)
#include <sys/inotify.h>
#include <limits.h>
#include <stdio.h>
int
rumpcomp_shmif_watchsetup(int *inotifyp, int fd)
{
char procbuf[PATH_MAX], linkbuf[PATH_MAX];
ssize_t nn;
int inotify, rv;
inotify = *inotifyp;
if (inotify == -1) {
inotify = inotify_init();
if (inotify == -1) {
rv = errno;
goto out;
}
}
/* ok, need to map fd into path for inotify */
snprintf(procbuf, sizeof(procbuf), "/proc/self/fd/%d", fd);
nn = readlink(procbuf, linkbuf, sizeof(linkbuf)-1);
if (nn >= (ssize_t)sizeof(linkbuf)-1) {
nn = -1;
errno = E2BIG; /* pick something */
}
if (nn == -1) {
rv = errno;
close(inotify);
goto out;
}
linkbuf[nn] = '\0';
if (inotify_add_watch(inotify, linkbuf, IN_MODIFY) == -1) {
rv = errno;
close(inotify);
goto out;
}
rv = 0;
*inotifyp = inotify;
out:
return rumpuser_component_errtrans(rv);
}
int
rumpcomp_shmif_watchwait(int kq)
{
struct inotify_event iev;
void *cookie;
ssize_t nn;
int rv;
cookie = rumpuser_component_unschedule();
do {
nn = read(kq, &iev, sizeof(iev));
} while (nn == -1 && errno == EINTR);
if (nn == -1) {
rv = errno;
} else {
rv = 0;
}
rumpuser_component_schedule(cookie);
return rumpuser_component_errtrans(rv);
}
#else
#include <stdio.h>
/* a polling default implementation */
int
rumpcomp_shmif_watchsetup(int *nono, int fd)
{
static int warned = 0;
if (!warned) {
fprintf(stderr, "WARNING: rumpuser writewatchfile routines are "
"polling-only on this platform\n");
warned = 1;
}
return 0;
}
int
rumpcomp_shmif_watchwait(int kq)
{
void *cookie;
cookie = rumpuser_component_unschedule();
usleep(10000);
rumpuser_component_schedule(cookie);
return 0;
}
#endif
int
rumpcomp_shmif_mmap(int fd, size_t len, void **memp)
{
void *mem;
int rv;
if (ftruncate(fd, len) == -1) {
rv = errno;
goto out;
}
#if defined(__sun__) && !defined(MAP_FILE)
#define MAP_FILE 0
#endif
mem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0);
if (mem == MAP_FAILED) {
rv = errno;
} else {
rv = 0;
*memp = mem;
}
out:
return rumpuser_component_errtrans(rv);
}
#endif