lib/librefuse: Implement FUSE session API and its signal handling functionality

This commit is contained in:
pho 2022-01-22 07:53:05 +00:00
parent 153b9c141b
commit 9f39150738
12 changed files with 515 additions and 13 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.1287 2022/01/10 10:02:30 martin Exp $ # $NetBSD: mi,v 1.1288 2022/01/22 07:53:05 pho Exp $
# #
# Note: Don't delete entries from here - mark them as "obsolete" instead, # Note: Don't delete entries from here - mark them as "obsolete" instead,
# unless otherwise stated below. # unless otherwise stated below.
@ -1147,6 +1147,7 @@
./usr/include/protocols base-c-usr ./usr/include/protocols base-c-usr
./usr/include/quota base-obsolete obsolete ./usr/include/quota base-obsolete obsolete
./usr/include/readline base-c-usr ./usr/include/readline base-c-usr
./usr/include/refuse base-refuse-usr
./usr/include/rpc base-c-usr ./usr/include/rpc base-c-usr
./usr/include/rpcsvc base-c-usr ./usr/include/rpcsvc base-c-usr
./usr/include/rump base-c-usr ./usr/include/rump base-c-usr

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.2404 2022/01/22 07:38:45 pho Exp $ # $NetBSD: mi,v 1.2405 2022/01/22 07:53:05 pho Exp $
# #
# Note: don't delete entries from here - mark them as "obsolete" instead. # Note: don't delete entries from here - mark them as "obsolete" instead.
./etc/mtree/set.comp comp-sys-root ./etc/mtree/set.comp comp-sys-root
@ -3092,6 +3092,7 @@
./usr/include/readline.h comp-obsolete obsolete ./usr/include/readline.h comp-obsolete obsolete
./usr/include/readline/history.h comp-c-include ./usr/include/readline/history.h comp-c-include
./usr/include/readline/readline.h comp-c-include ./usr/include/readline/readline.h comp-c-include
./usr/include/refuse/session.h comp-refuse-include
./usr/include/regex.h comp-c-include ./usr/include/regex.h comp-c-include
./usr/include/regexp.h comp-c-include ./usr/include/regexp.h comp-c-include
./usr/include/res_update.h comp-c-include ./usr/include/res_update.h comp-c-include

View File

@ -1,4 +1,4 @@
# $NetBSD: NetBSD.dist.base,v 1.240 2021/12/13 23:59:35 maya Exp $ # $NetBSD: NetBSD.dist.base,v 1.241 2022/01/22 07:53:06 pho Exp $
# @(#)4.4BSD.dist 8.1 (Berkeley) 6/13/93 # @(#)4.4BSD.dist 8.1 (Berkeley) 6/13/93
# Do not customize this file as it may be overwritten on upgrades. # Do not customize this file as it may be overwritten on upgrades.
@ -326,6 +326,7 @@
./usr/include/prop ./usr/include/prop
./usr/include/protocols ./usr/include/protocols
./usr/include/readline ./usr/include/readline
./usr/include/refuse
./usr/include/rpc ./usr/include/rpc
./usr/include/rpcsvc ./usr/include/rpcsvc
./usr/include/rump ./usr/include/rump

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.13 2022/01/22 07:38:45 pho Exp $ # $NetBSD: Makefile,v 1.14 2022/01/22 07:53:06 pho Exp $
USE_FORT?= yes # data driven bugs? USE_FORT?= yes # data driven bugs?
@ -13,10 +13,12 @@ FUSE_OPT_DEBUG_FLAGS= -g -DFUSE_OPT_DEBUG
CFLAGS+= ${FUSE_OPT_DEBUG_FLAGS} CFLAGS+= ${FUSE_OPT_DEBUG_FLAGS}
CPPFLAGS+= -I${.CURDIR} CPPFLAGS+= -I${.CURDIR}
SRCS= refuse.c refuse_log.c refuse_lowlevel.c SRCS= refuse.c refuse_log.c refuse_lowlevel.c
SRCS+= refuse_opt.c SRCS+= refuse_opt.c refuse_signals.c
MAN= refuse.3 MAN= refuse.3
WARNS?= 5 WARNS?= 5
INCS= fuse.h fuse_opt.h fuse_log.h fuse_lowlevel.h INCS= fuse.h fuse_opt.h fuse_log.h fuse_lowlevel.h
INCSDIR= /usr/include INCSDIR= /usr/include
.include "${.CURDIR}/refuse/Makefile.inc"
.include <bsd.lib.mk> .include <bsd.lib.mk>

View File

@ -1,4 +1,4 @@
/* $NetBSD: fuse.h,v 1.24 2021/12/04 06:42:39 pho Exp $ */ /* $NetBSD: fuse.h,v 1.25 2022/01/22 07:53:06 pho Exp $ */
/* /*
* Copyright © 2007 Alistair Crooks. All rights reserved. * Copyright © 2007 Alistair Crooks. All rights reserved.
@ -30,9 +30,11 @@
#ifndef FUSE_H_ #ifndef FUSE_H_
#define FUSE_H_ 20211204 #define FUSE_H_ 20211204
#include <refuse/session.h>
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/types.h> #include <sys/types.h>
#include <puffs.h>
#include <utime.h> #include <utime.h>
/* The latest version of FUSE API currently provided by refuse. */ /* The latest version of FUSE API currently provided by refuse. */

View File

@ -1,4 +1,4 @@
/* $NetBSD: fuse_internal.h,v 1.1 2021/12/04 06:42:39 pho Exp $ */ /* $NetBSD: fuse_internal.h,v 1.2 2022/01/22 07:53:06 pho Exp $ */
/* /*
* Copyright (c) 2021 The NetBSD Foundation, Inc. * Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -38,5 +38,20 @@
#include <fuse.h> #include <fuse.h>
#include <fuse_lowlevel.h> #include <fuse_lowlevel.h>
#include <sys/cdefs.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Internal functions, hidden from users */
__BEGIN_HIDDEN_DECLS
int __fuse_set_signal_handlers(struct fuse* fuse);
int __fuse_remove_signal_handlers(struct fuse* fuse);
__END_HIDDEN_DECLS
#ifdef __cplusplus
}
#endif
#endif #endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: refuse.c,v 1.103 2021/12/04 06:42:39 pho Exp $ */ /* $NetBSD: refuse.c,v 1.104 2022/01/22 07:53:06 pho Exp $ */
/* /*
* Copyright © 2007 Alistair Crooks. All rights reserved. * Copyright © 2007 Alistair Crooks. All rights reserved.
@ -31,7 +31,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#if !defined(lint) #if !defined(lint)
__RCSID("$NetBSD: refuse.c,v 1.103 2021/12/04 06:42:39 pho Exp $"); __RCSID("$NetBSD: refuse.c,v 1.104 2022/01/22 07:53:06 pho Exp $");
#endif /* !lint */ #endif /* !lint */
/* We emit a compiler warning for anyone including <fuse.h> without /* We emit a compiler warning for anyone including <fuse.h> without
@ -47,6 +47,8 @@ __RCSID("$NetBSD: refuse.c,v 1.103 2021/12/04 06:42:39 pho Exp $");
#include <fuse_internal.h> #include <fuse_internal.h>
#include <fuse_opt.h> #include <fuse_opt.h>
#include <paths.h> #include <paths.h>
#include <puffs.h>
#include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>

View File

@ -0,0 +1,7 @@
# $NetBSD: Makefile.inc,v 1.1 2022/01/22 07:53:06 pho Exp $
.PATH: ${.CURDIR}/refuse
SRCS+= session.c
INCS+= refuse/session.h

View File

@ -0,0 +1,70 @@
/* $NetBSD: session.c,v 1.1 2022/01/22 07:53:06 pho Exp $ */
/*
* Copyright (c) 2021 The NetBSD Foundation, Inc.
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* 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 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>
#if !defined(lint)
__RCSID("$NetBSD: session.c,v 1.1 2022/01/22 07:53:06 pho Exp $");
#endif /* !lint */
#include <err.h>
#include <fuse_internal.h>
#include <puffs.h>
/* The documentation for FUSE is not clear as to what "struct fuse_session" is,
* why it exists, or how it's different from "struct fuse". For now we leave it
* undefined (i.e. an incomplete type) and treat "struct fuse_session *" as
* being identical to "struct fuse *". */
struct fuse_session *
fuse_get_session(struct fuse *f) {
return (struct fuse_session*)f;
}
int
fuse_session_fd(struct fuse_session *se) {
struct fuse* fuse = (struct fuse*)se;
/* We don't want to expose this to users, but filesystems in the wild often
* wants to set FD_CLOEXEC on it. Hope they don't assume it's the real
* /dev/fuse, because it's actually /dev/puffs in our implementation. */
return puffs_getselectable(fuse->pu);
}
int
fuse_set_signal_handlers(struct fuse_session *se) {
return __fuse_set_signal_handlers((struct fuse*)se);
}
void
fuse_remove_signal_handlers(struct fuse_session *se) {
if (__fuse_remove_signal_handlers((struct fuse*)se) == -1)
warn("%s: failed to remove signal handlers", __func__);
}

View File

@ -0,0 +1,69 @@
/* $NetBSD: session.h,v 1.1 2022/01/22 07:53:06 pho Exp $ */
/*
* Copyright (c) 2021 The NetBSD Foundation, Inc.
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* 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 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.
*/
#if !defined(_FUSE_SESSION_H_)
#define _FUSE_SESSION_H_
/* FUSE session API
*/
#if !defined(FUSE_H_)
# error Do not include this header directly. Include <fuse.h> instead.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Forward declarations */
struct fuse;
/* A private structure appeared on FUSE 2.4. */
struct fuse_session;
/* Get a session from a fuse object. Appeared on FUSE 2.6. */
struct fuse_session *fuse_get_session(struct fuse *f);
/* Get the file descriptor for communicaiton with kernel. Appeared on
* FUSE 3.0. */
int fuse_session_fd(struct fuse_session *se);
/* Exit a session on SIGHUP, SIGTERM, and SIGINT and ignore
* SIGPIPE. Appeared on FUSE 2.5. */
int fuse_set_signal_handlers(struct fuse_session *se);
/* Restore default signal handlers. Appeared on FUSE 2.5. */
void fuse_remove_signal_handlers(struct fuse_session *se);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,331 @@
/* $NetBSD: refuse_signals.c,v 1.1 2022/01/22 07:53:06 pho Exp $ */
/*
* Copyright (c) 2021 The NetBSD Foundation, Inc.
* 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.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* 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 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>
#if !defined(lint)
__RCSID("$NetBSD: refuse_signals.c,v 1.1 2022/01/22 07:53:06 pho Exp $");
#endif /* !lint */
#include <assert.h>
#include <fuse_internal.h>
#if defined(MULTITHREADED_REFUSE)
# include <pthread.h>
#endif
#include <signal.h>
#include <stdlib.h>
#include <string.h>
/* Signal handling routines
*
* FUSE only supports running a single filesystem per process. ReFUSE
* is going to allow a process to run a filesystem per thread. In
* order to support this, our implementation of
* fuse_set_signal_handlers() installs a set of signal handlers which,
* when invoked, terminates all the filesystems that called the
* function. This means our fuse_remove_signal_handlers() must not
* actually remove the signal handlers until the last thread calls the
* function.
*
* FUSE installs a signal handler for a signal only if its sa_handler
* is set to SIG_DFL. This obviously has a bad consequence: if the
* caller process already has a non-default signal handler for SIGINT,
* Ctrl-C will not stop the main loop of FUSE. See
* https://stackoverflow.com/q/5044375/3571336
*
* Maybe we should do the same knowing it's bad, but it's probably
* better to call our handler along with the old one. We may change
* this behavior if this turns out to cause serious compatibility
* issues.
*
* Also note that it is tempting to use puffs_unmountonsignal(3) but
* we can't, because there is no way to revert its effect.
*/
#if defined(MULTITHREADED_REFUSE)
/* A mutex to protect the global state regarding signal handlers. When
* a thread is going to lock this, it must block all the signals (with
* pthread_sigmask(3)) that we install a handler for, or otherwise it
* may deadlock for trying to acquire a lock that is already held by
* itself. */
static pthread_mutex_t signal_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif
/* Saved sigaction for each signal before we modify them. */
static struct sigaction* saved_actions[NSIG];
/* A linked list of "struct fuse*" which should be terminated upon
* receiving a signal. */
struct refuse_obj_elem {
struct fuse* fuse;
struct refuse_obj_elem* next;
};
static struct refuse_obj_elem* fuse_head;
#if defined(MULTITHREADED_REFUSE)
static int
block_signals(sigset_t* oset) {
sigset_t set;
if (sigemptyset(&set) != 0)
return -1;
if (sigaddset(&set, SIGHUP) != 0)
return -1;
if (sigaddset(&set, SIGINT) != 0)
return -1;
if (sigaddset(&set, SIGTERM) != 0)
return -1;
return pthread_sigmask(SIG_BLOCK, &set, oset);
}
static int
unblock_signals(const sigset_t* oset) {
return pthread_sigmask(SIG_SETMASK, oset, NULL);
}
#endif /* defined(MULTITHREADED_REFUSE) */
/* handler == NULL means the signal should be ignored. */
static int
set_signal_handler(int sig, void (*handler)(int, siginfo_t*, void*)) {
struct sigaction* saved;
struct sigaction act;
saved = malloc(sizeof(*saved));
if (!saved)
return -1;
if (sigaction(sig, NULL, saved) != 0) {
free(saved);
return -1;
}
saved_actions[sig] = saved;
memset(&act, 0, sizeof(act));
if (handler) {
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;
}
else {
/* Ignore the signal only if the signal doesn't have a
* handler. */
if (!(saved->sa_flags & SA_SIGINFO) && saved->sa_handler == SIG_DFL)
act.sa_handler = SIG_IGN;
else
return 0;
}
if (sigemptyset(&act.sa_mask) != 0) {
free(saved);
saved_actions[sig] = NULL;
return -1;
}
return sigaction(sig, &act, NULL);
}
static int
restore_signal_handler(int sig, void (*handler)(int, siginfo_t*, void*)) {
struct sigaction oact;
struct sigaction* saved;
saved = saved_actions[sig];
assert(saved != NULL);
if (sigaction(sig, NULL, &oact) != 0)
return -1;
/* Has the sigaction changed since we installed our handler? Do
* nothing if so. */
if (handler) {
if (!(oact.sa_flags & SA_SIGINFO) || oact.sa_sigaction != handler)
goto done;
}
else {
if (oact.sa_handler != SIG_IGN)
goto done;
}
if (sigaction(sig, saved, NULL) != 0)
return -1;
done:
free(saved);
saved_actions[sig] = NULL;
return 0;
}
static void
exit_handler(int sig, siginfo_t* info, void* ctx) {
struct refuse_obj_elem* elem;
struct sigaction* saved;
#if defined(MULTITHREADED_REFUSE)
int rv;
/* pthread_mutex_lock(3) is NOT an async-signal-safe function. We
* assume it's okay, as the thread running this handler shouldn't
* be locking this mutex. */
rv = pthread_mutex_lock(&signal_mutex);
assert(rv == 0);
#endif
for (elem = fuse_head; elem != NULL; elem = elem->next)
fuse_exit(elem->fuse);
#if defined(MULTITHREADED_REFUSE)
rv = pthread_mutex_unlock(&signal_mutex);
assert(rv == 0);
#endif
saved = saved_actions[sig];
assert(saved != NULL);
if (saved->sa_handler != SIG_DFL && saved->sa_handler != SIG_IGN) {
if (saved->sa_flags & SA_SIGINFO)
saved->sa_sigaction(sig, info, ctx);
else
saved->sa_handler(sig);
}
}
/* The original function appeared on FUSE 2.5 takes a pointer to
* "struct fuse_session" instead of "struct fuse". We have no such
* things as fuse sessions.
*/
int
__fuse_set_signal_handlers(struct fuse* fuse) {
int ret = 0;
struct refuse_obj_elem* elem;
#if defined(MULTITHREADED_REFUSE)
int rv;
sigset_t oset;
rv = block_signals(&oset);
assert(rv == 0);
rv = pthread_mutex_lock(&signal_mutex);
assert(rv == 0);
#endif
/* Have we already installed our signal handlers? If the list is
* empty, it means we have not. */
if (fuse_head == NULL) {
if (set_signal_handler(SIGHUP, exit_handler) != 0 ||
set_signal_handler(SIGINT, exit_handler) != 0 ||
set_signal_handler(SIGTERM, exit_handler) != 0 ||
set_signal_handler(SIGPIPE, NULL) != 0) {
ret = -1;
goto done;
}
}
/* Add ourselves to the list of filesystems that want to be
* terminated upon receiving a signal. But only if we aren't
* already in the list. */
for (elem = fuse_head; elem != NULL; elem = elem->next) {
if (elem->fuse == fuse)
goto done;
}
elem = malloc(sizeof(*elem));
if (!elem) {
ret = -1;
goto done;
}
elem->fuse = fuse;
elem->next = fuse_head;
fuse_head = elem;
done:
#if defined(MULTITHREADED_REFUSE)
rv = pthread_mutex_unlock(&signal_mutex);
assert(rv == 0);
rv = unblock_signals(&oset);
assert(rv == 0);
#endif
return ret;
}
int
__fuse_remove_signal_handlers(struct fuse* fuse) {
int ret = 0;
struct refuse_obj_elem* prev;
struct refuse_obj_elem* elem;
#if defined(MULTITHREADED_REFUSE)
int rv;
sigset_t oset;
rv = block_signals(&oset);
assert(rv == 0);
rv = pthread_mutex_lock(&signal_mutex);
assert(rv == 0);
#endif
/* Remove ourselves from the list. */
for (prev = NULL, elem = fuse_head;
elem != NULL;
prev = elem, elem = elem->next) {
if (elem->fuse == fuse) {
if (prev)
prev->next = elem->next;
else
fuse_head = elem->next;
free(elem);
}
}
/* Restore handlers if we were the last one. */
if (fuse_head == NULL) {
if (restore_signal_handler(SIGHUP, exit_handler) == -1 ||
restore_signal_handler(SIGINT, exit_handler) == -1 ||
restore_signal_handler(SIGTERM, exit_handler) == -1 ||
restore_signal_handler(SIGPIPE, NULL) == -1) {
ret = -1;
}
}
#if defined(MULTITHREADED_REFUSE)
rv = pthread_mutex_unlock(&signal_mutex);
assert(rv == 0);
rv = unblock_signals(&oset);
assert(rv == 0);
#endif
return ret;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: fwcfg.c,v 1.6 2021/12/04 06:42:39 pho Exp $ */ /* $NetBSD: fwcfg.c,v 1.7 2022/01/22 07:53:06 pho Exp $ */
/*- /*-
* Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca> * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
@ -27,11 +27,12 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__RCSID("$NetBSD: fwcfg.c,v 1.6 2021/12/04 06:42:39 pho Exp $"); __RCSID("$NetBSD: fwcfg.c,v 1.7 2022/01/22 07:53:06 pho Exp $");
#define FUSE_USE_VERSION FUSE_MAKE_VERSION(2, 6) #define FUSE_USE_VERSION FUSE_MAKE_VERSION(2, 6)
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/param.h>
#include <err.h> #include <err.h>
#include <errno.h> #include <errno.h>