Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 29 Apr 2020 16:24:33 +0000 (UTC)
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r360470 - in vendor/lib9p: . dist dist/backend dist/example dist/pytest dist/sbuf dist/transport
Message-ID:  <202004291624.03TGOXsf023532@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jceel
Date: Wed Apr 29 16:24:32 2020
New Revision: 360470
URL: https://svnweb.freebsd.org/changeset/base/360470

Log:
  Import lib9p 7ddb1164407da19b9b1afb83df83ae65a71a9a66.
  
  Approved by:	trasz (mentor)
  MFC after:	1 month
  Sponsored by:	Conclusive Engineering

Added:
  vendor/lib9p/
  vendor/lib9p/dist/
  vendor/lib9p/dist/.gitignore
  vendor/lib9p/dist/COPYRIGHT
  vendor/lib9p/dist/GNUmakefile
  vendor/lib9p/dist/Makefile   (contents, props changed)
  vendor/lib9p/dist/README.md
  vendor/lib9p/dist/apple_endian.h   (contents, props changed)
  vendor/lib9p/dist/backend/
  vendor/lib9p/dist/backend/backend.h   (contents, props changed)
  vendor/lib9p/dist/backend/fs.c   (contents, props changed)
  vendor/lib9p/dist/backend/fs.h   (contents, props changed)
  vendor/lib9p/dist/connection.c   (contents, props changed)
  vendor/lib9p/dist/example/
  vendor/lib9p/dist/example/Makefile   (contents, props changed)
  vendor/lib9p/dist/example/server.c   (contents, props changed)
  vendor/lib9p/dist/fcall.h   (contents, props changed)
  vendor/lib9p/dist/fid.h   (contents, props changed)
  vendor/lib9p/dist/genacl.c   (contents, props changed)
  vendor/lib9p/dist/genacl.h   (contents, props changed)
  vendor/lib9p/dist/hashtable.c   (contents, props changed)
  vendor/lib9p/dist/hashtable.h   (contents, props changed)
  vendor/lib9p/dist/lib9p.h   (contents, props changed)
  vendor/lib9p/dist/lib9p_impl.h   (contents, props changed)
  vendor/lib9p/dist/linux_errno.h   (contents, props changed)
  vendor/lib9p/dist/log.c   (contents, props changed)
  vendor/lib9p/dist/log.h   (contents, props changed)
  vendor/lib9p/dist/pack.c   (contents, props changed)
  vendor/lib9p/dist/pytest/
  vendor/lib9p/dist/pytest/.gitignore
  vendor/lib9p/dist/pytest/Makefile   (contents, props changed)
  vendor/lib9p/dist/pytest/README
  vendor/lib9p/dist/pytest/client.py   (contents, props changed)
  vendor/lib9p/dist/pytest/lerrno.py   (contents, props changed)
  vendor/lib9p/dist/pytest/numalloc.py   (contents, props changed)
  vendor/lib9p/dist/pytest/p9conn.py   (contents, props changed)
  vendor/lib9p/dist/pytest/p9err.py   (contents, props changed)
  vendor/lib9p/dist/pytest/pfod.py   (contents, props changed)
  vendor/lib9p/dist/pytest/protocol.py   (contents, props changed)
  vendor/lib9p/dist/pytest/sequencer.py   (contents, props changed)
  vendor/lib9p/dist/pytest/testconf.ini.sample
  vendor/lib9p/dist/request.c   (contents, props changed)
  vendor/lib9p/dist/rfuncs.c   (contents, props changed)
  vendor/lib9p/dist/rfuncs.h   (contents, props changed)
  vendor/lib9p/dist/sbuf/
  vendor/lib9p/dist/sbuf/sbuf.c   (contents, props changed)
  vendor/lib9p/dist/sbuf/sbuf.h   (contents, props changed)
  vendor/lib9p/dist/threadpool.c   (contents, props changed)
  vendor/lib9p/dist/threadpool.h   (contents, props changed)
  vendor/lib9p/dist/transport/
  vendor/lib9p/dist/transport/socket.c   (contents, props changed)
  vendor/lib9p/dist/transport/socket.h   (contents, props changed)
  vendor/lib9p/dist/utils.c   (contents, props changed)

Added: vendor/lib9p/dist/.gitignore
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/.gitignore	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,37 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+/build/
+
+*.po
+*.pico
+*.depend

Added: vendor/lib9p/dist/COPYRIGHT
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/COPYRIGHT	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,47 @@
+Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
+All rights reserved
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted providing 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 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.
+
+Some parts of the code are based on libixp (http://libs.suckless.org/libixp)
+library code released under following license:
+
+© 2005-2006 Anselm R. Garbe <garbeam@gmail.com>
+© 2006-2010 Kris Maglione <maglione.k at Gmail>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.

Added: vendor/lib9p/dist/GNUmakefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/GNUmakefile	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,76 @@
+CC_VERSION := $(shell $(CC) --version | \
+    sed -n -e '/clang-/s/.*clang-\([0-9][0-9]*\).*/\1/p')
+ifeq ($(CC_VERSION),)
+# probably not clang
+CC_VERSION := 0
+endif
+
+WFLAGS :=
+
+# Warnings are version-dependent, unfortunately,
+# so test for version before adding a -W flag.
+# Note: gnu make requires $(shell test ...) for "a > b" type tests.
+ifeq ($(shell test $(CC_VERSION) -gt 0; echo $$?),0)
+WFLAGS += -Weverything
+WFLAGS += -Wno-padded
+WFLAGS += -Wno-gnu-zero-variadic-macro-arguments
+WFLAGS += -Wno-format-nonliteral
+WFLAGS += -Wno-unused-macros
+WFLAGS += -Wno-disabled-macro-expansion
+WFLAGS += -Werror
+endif
+
+ifeq ($(shell test $(CC_VERSION) -gt 600; echo $$?),0)
+WFLAGS += -Wno-reserved-id-macro
+endif
+
+CFLAGS := $(WFLAGS) \
+	-g \
+	-O0 \
+	-DL9P_DEBUG=L9P_DEBUG
+# Note: to turn on debug, use -DL9P_DEBUG=L9P_DEBUG,
+# and set env variable LIB9P_LOGGING to stderr or to
+# the (preferably full path name of) the debug log file.
+
+LIB_SRCS := \
+	pack.c \
+	connection.c \
+	request.c \
+	genacl.c \
+	log.c \
+	hashtable.c \
+	utils.c \
+	rfuncs.c \
+	threadpool.c \
+	sbuf/sbuf.c \
+	transport/socket.c \
+	backend/fs.c
+
+SERVER_SRCS := \
+	example/server.c
+
+BUILD_DIR := build
+LIB_OBJS := $(addprefix build/,$(LIB_SRCS:.c=.o))
+SERVER_OBJS := $(SERVER_SRCS:.c=.o)
+LIB := lib9p.dylib
+SERVER := server
+
+all: build $(LIB) $(SERVER)
+
+$(LIB): $(LIB_OBJS)
+	cc -dynamiclib $^ -o build/$@
+
+$(SERVER): $(SERVER_OBJS) $(LIB)
+	cc $< -o build/$(SERVER) -Lbuild/ -l9p
+
+clean:
+	rm -rf build
+	rm -f $(SERVER_OBJS)
+build:
+	mkdir build
+	mkdir build/sbuf
+	mkdir build/transport
+	mkdir build/backend
+
+build/%.o: %.c
+	$(CC) $(CFLAGS) -c $< -o $@

Added: vendor/lib9p/dist/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/Makefile	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,27 @@
+# Note: to turn on debug, use -DL9P_DEBUG=L9P_DEBUG,
+# and set env variable LIB9P_LOGGING to stderr or to
+# the (preferably full path name of) the debug log file.
+
+LIB=		9p
+SHLIB_MAJOR=	1
+SRCS=		pack.c \
+		connection.c \
+		request.c log.c \
+		hashtable.c \
+		genacl.c \
+		utils.c \
+		rfuncs.c \
+		threadpool.c \
+		transport/socket.c \
+		backend/fs.c
+
+INCS=		lib9p.h
+CC=		clang
+CFLAGS=		-g -O0 -DL9P_DEBUG=L9P_DEBUG -DWITH_CASPER
+LIBADD=		sbuf libcasper libcap_pwd libcap_grp
+SUBDIR=		example
+
+cscope: .PHONY
+	cd ${.CURDIR}; cscope -buq $$(find . -name '*.[ch]' -print)
+
+.include <bsd.lib.mk>

Added: vendor/lib9p/dist/README.md
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/README.md	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,20 @@
+# lib9p
+
+lib9p is a server library implementing 9p2000, 9p2000.u and 9p2000.L revisions
+of 9P protocol. It is being developed primarily as a backend for virtio-9p in
+BHyVe, the FreeBSD hypervisor.
+
+# Features
+
+* 9p2000, 9p2000.u and 9p2000.L protocol support
+* Built-in TCP transport
+
+# Supported operating systems
+
+* FreeBSD (>=10)
+* macOS (>=10.9)
+
+# Authors
+
+* Jakub Klama [jceel](https://github.com/jceel)
+* Chris Torek [chris3torek](https://github.com/chris3torek)

Added: vendor/lib9p/dist/apple_endian.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/apple_endian.h	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,27 @@
+#ifndef _APPLE_ENDIAN_H
+#define _APPLE_ENDIAN_H
+
+/*
+ * Shims to make Apple's endian headers and macros compatible
+ * with <sys/endian.h> (which is awful).
+ */
+
+# include <libkern/OSByteOrder.h>
+
+# define _LITTLE_ENDIAN 0x12345678
+# define _BIG_ENDIAN 0x87654321
+
+# ifdef __LITTLE_ENDIAN__
+#  define _BYTE_ORDER _LITTLE_ENDIAN
+# endif
+# ifdef __BIG_ENDIAN__
+#  define _BYTE_ORDER _BIG_ENDIAN
+# endif
+
+# define htole32(x)	OSSwapHostToLittleInt32(x)
+# define le32toh(x)	OSSwapLittleToHostInt32(x)
+
+# define htobe32(x)	OSSwapHostToBigInt32(x)
+# define be32toh(x)	OSSwapBigToHostInt32(x)
+
+#endif /* _APPLE_ENDIAN_H */

Added: vendor/lib9p/dist/backend/backend.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/backend/backend.h	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing 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 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 LIB9P_BACKEND_H
+#define LIB9P_BACKEND_H
+
+struct l9p_backend {
+	void *softc;
+	void (*freefid)(void *, struct l9p_fid *);
+	int (*attach)(void *, struct l9p_request *);
+	int (*clunk)(void *, struct l9p_fid *);
+	int (*create)(void *, struct l9p_request *);
+	int (*open)(void *, struct l9p_request *);
+	int (*read)(void *, struct l9p_request *);
+	int (*remove)(void *, struct l9p_fid *);
+	int (*stat)(void *, struct l9p_request *);
+	int (*walk)(void *, struct l9p_request *);
+	int (*write)(void *, struct l9p_request *);
+	int (*wstat)(void *, struct l9p_request *);
+	int (*statfs)(void *, struct l9p_request *);
+	int (*lopen)(void *, struct l9p_request *);
+	int (*lcreate)(void *, struct l9p_request *);
+	int (*symlink)(void *, struct l9p_request *);
+	int (*mknod)(void *, struct l9p_request *);
+	int (*rename)(void *, struct l9p_request *);
+	int (*readlink)(void *, struct l9p_request *);
+	int (*getattr)(void *, struct l9p_request *);
+	int (*setattr)(void *, struct l9p_request *);
+	int (*xattrwalk)(void *, struct l9p_request *);
+	int (*xattrcreate)(void *, struct l9p_request *);
+	int (*xattrread)(void *, struct l9p_request *);
+	int (*xattrwrite)(void *, struct l9p_request *);
+	int (*xattrclunk)(void *, struct l9p_fid *);
+	int (*readdir)(void *, struct l9p_request *);
+	int (*fsync)(void *, struct l9p_request *);
+	int (*lock)(void *, struct l9p_request *);
+	int (*getlock)(void *, struct l9p_request *);
+	int (*link)(void *, struct l9p_request *);
+	int (*mkdir)(void *, struct l9p_request *);
+	int (*renameat)(void *, struct l9p_request *);
+	int (*unlinkat)(void *, struct l9p_request *);
+};
+
+#endif  /* LIB9P_BACKEND_H */

Added: vendor/lib9p/dist/backend/fs.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/lib9p/dist/backend/fs.c	Wed Apr 29 16:24:32 2020	(r360470)
@@ -0,0 +1,3061 @@
+/*
+ * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
+ * All rights reserved
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted providing 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 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.
+ *
+ */
+
+/*
+ * Based on libixp code: ©2007-2010 Kris Maglione <maglione.k at Gmail>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <libgen.h>
+#include <pthread.h>
+#include "../lib9p.h"
+#include "../lib9p_impl.h"
+#include "../fid.h"
+#include "../log.h"
+#include "../rfuncs.h"
+#include "../genacl.h"
+#include "backend.h"
+#include "fs.h"
+
+#if defined(WITH_CASPER)
+  #include <libcasper.h>
+  #include <casper/cap_pwd.h>
+  #include <casper/cap_grp.h>
+#endif
+
+#if defined(__FreeBSD__)
+  #include <sys/param.h>
+  #if __FreeBSD_version >= 1000000
+    #define	HAVE_BINDAT
+  #endif
+#endif
+
+#if defined(__FreeBSD__)
+  #define	HAVE_BIRTHTIME
+#endif
+
+#if defined(__APPLE__)
+  #include <sys/syscall.h>
+  #include "Availability.h"
+  #define ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+#endif
+
+struct fs_softc {
+	int 	fs_rootfd;
+	bool	fs_readonly;
+#if defined(WITH_CASPER)
+	cap_channel_t *fs_cappwd;
+	cap_channel_t *fs_capgrp;
+#endif
+};
+
+struct fs_fid {
+	DIR	*ff_dir;
+	int	ff_dirfd;
+	int	ff_fd;
+	int	ff_flags;
+	char	*ff_name;
+	struct fs_authinfo *ff_ai;
+	pthread_mutex_t ff_mtx;
+	struct l9p_acl *ff_acl; /* cached ACL if any */
+};
+
+#define	FF_NO_NFSV4_ACL	0x01	/* don't go looking for NFSv4 ACLs */
+/*	FF_NO_POSIX_ACL	0x02	-- not yet */
+
+/*
+ * Our authinfo consists of:
+ *
+ *  - a reference count
+ *  - a uid
+ *  - a gid-set
+ *
+ * The "default" gid is the first gid in the git-set, provided the
+ * set size is at least 1.  The set-size may be zero, though.
+ *
+ * Adjustments to the ref-count must be atomic, once it's shared.
+ * It would be nice to use C11 atomics here but they are not common
+ * enough to all systems just yet; for now, we use a mutex.
+ *
+ * Note that some ops (Linux style ones) pass an effective gid for
+ * the op, in which case, that gid may override.  To achieve this
+ * effect, permissions testing functions also take an extra gid.
+ * If this gid is (gid_t)-1 it is not used and only the remaining
+ * gids take part.
+ *
+ * The uid may also be (uid_t)-1, meaning "no uid was available
+ * at all at attach time".  In this case, new files inherit parent
+ * directory uids.
+ *
+ * The refcount is simply the number of "openfile"s using this
+ * authinfo (so that when the last ref goes away, we can free it).
+ *
+ * There are also master ACL flags (same as in ff_flags).
+ */
+struct fs_authinfo {
+	pthread_mutex_t ai_mtx;	/* lock for refcnt */
+	uint32_t ai_refcnt;
+	int	ai_flags;
+	uid_t	ai_uid;
+	int	ai_ngids;
+	gid_t	ai_gids[];	/* NB: flexible array member */
+};
+
+/*
+ * We have a global-static mutex for single-threading Tattach
+ * requests, which use getpwnam (and indirectly, getgr* functions)
+ * which are not reentrant.
+ */
+static bool fs_attach_mutex_inited;
+static pthread_mutex_t fs_attach_mutex;
+
+/*
+ * Internal functions (except inline functions).
+ */
+static struct passwd *fs_getpwuid(struct fs_softc *, uid_t, struct r_pgdata *);
+static struct group *fs_getgrgid(struct fs_softc *, gid_t, struct r_pgdata *);
+static int fs_buildname(struct l9p_fid *, char *, char *, size_t);
+static int fs_pdir(struct fs_softc *, struct l9p_fid *, char *, size_t,
+    struct stat *st);
+static int fs_dpf(char *, char *, size_t);
+static int fs_oflags_dotu(int, int *);
+static int fs_oflags_dotl(uint32_t, int *, enum l9p_omode *);
+static int fs_nde(struct fs_softc *, struct l9p_fid *, bool, gid_t,
+    struct stat *, uid_t *, gid_t *);
+static struct fs_fid *open_fid(int, const char *, struct fs_authinfo *, bool);
+static void dostat(struct fs_softc *, struct l9p_stat *, char *,
+    struct stat *, bool dotu);
+static void dostatfs(struct l9p_statfs *, struct statfs *, long);
+static void fillacl(struct fs_fid *ff);
+static struct l9p_acl *getacl(struct fs_fid *ff, int fd, const char *path);
+static void dropacl(struct fs_fid *ff);
+static struct l9p_acl *look_for_nfsv4_acl(struct fs_fid *ff, int fd,
+    const char *path);
+static int check_access(int32_t,
+    struct l9p_acl *, struct stat *, struct l9p_acl *, struct stat *,
+    struct fs_authinfo *, gid_t);
+static void generate_qid(struct stat *, struct l9p_qid *);
+
+static int fs_icreate(void *, struct l9p_fid *, char *, int,
+    bool, mode_t, gid_t, struct stat *);
+static int fs_iopen(void *, struct l9p_fid *, int, enum l9p_omode,
+    gid_t, struct stat *);
+static int fs_imkdir(void *, struct l9p_fid *, char *,
+    bool, mode_t, gid_t, struct stat *);
+static int fs_imkfifo(void *, struct l9p_fid *, char *,
+    bool, mode_t, gid_t, struct stat *);
+static int fs_imknod(void *, struct l9p_fid *, char *,
+    bool, mode_t, dev_t, gid_t, struct stat *);
+static int fs_imksocket(void *, struct l9p_fid *, char *,
+    bool, mode_t, gid_t, struct stat *);
+static int fs_isymlink(void *, struct l9p_fid *, char *, char *,
+    gid_t, struct stat *);
+
+/*
+ * Internal functions implementing backend.
+ */
+static int fs_attach(void *, struct l9p_request *);
+static int fs_clunk(void *, struct l9p_fid *);
+static int fs_create(void *, struct l9p_request *);
+static int fs_open(void *, struct l9p_request *);
+static int fs_read(void *, struct l9p_request *);
+static int fs_remove(void *, struct l9p_fid *);
+static int fs_stat(void *, struct l9p_request *);
+static int fs_walk(void *, struct l9p_request *);
+static int fs_write(void *, struct l9p_request *);
+static int fs_wstat(void *, struct l9p_request *);
+static int fs_statfs(void *, struct l9p_request *);
+static int fs_lopen(void *, struct l9p_request *);
+static int fs_lcreate(void *, struct l9p_request *);
+static int fs_symlink(void *, struct l9p_request *);
+static int fs_mknod(void *, struct l9p_request *);
+static int fs_rename(void *, struct l9p_request *);
+static int fs_readlink(void *, struct l9p_request *);
+static int fs_getattr(void *, struct l9p_request *);
+static int fs_setattr(void *, struct l9p_request *);
+static int fs_xattrwalk(void *, struct l9p_request *);
+static int fs_xattrcreate(void *, struct l9p_request *);
+static int fs_readdir(void *, struct l9p_request *);
+static int fs_fsync(void *, struct l9p_request *);
+static int fs_lock(void *, struct l9p_request *);
+static int fs_getlock(void *, struct l9p_request *);
+static int fs_link(void *, struct l9p_request *);
+static int fs_renameat(void *, struct l9p_request *);
+static int fs_unlinkat(void *, struct l9p_request *);
+static void fs_freefid(void *, struct l9p_fid *);
+
+/*
+ * Convert from 9p2000 open/create mode to Unix-style O_* flags.
+ * This includes 9p2000.u extensions, but not 9p2000.L protocol,
+ * which has entirely different open, create, etc., flag bits.
+ *
+ * The <mode> given here is the one-byte (uint8_t) "mode"
+ * argument to Tcreate or Topen, so it can have at most 8 bits.
+ *
+ * https://swtch.com/plan9port/man/man9/open.html and
+ * http://plan9.bell-labs.com/magic/man2html/5/open
+ * both say:
+ *
+ *   The [low two bits of the] mode field determines the
+ *   type of I/O ... [I]f mode has the OTRUNC (0x10) bit
+ *   set, the file is to be truncated, which requires write
+ *   permission ...; if the mode has the ORCLOSE (0x40) bit
+ *   set, the file is to be removed when the fid is clunked,
+ *   which requires permission to remove the file from its
+ *   directory.  All other bits in mode should be zero.  It
+ *   is illegal to write a directory, truncate it, or
+ *   attempt to remove it on close.
+ *
+ * 9P2000.u may add ODIRECT (0x80); this is not completely clear.
+ * The fcall.h header defines OCEXEC (0x20) as well, but it makes
+ * no sense to send this to a server.  There seem to be no bits
+ * 0x04 and 0x08.
+ *
+ * We always turn on O_NOCTTY since as a server, we never want
+ * to gain a controlling terminal.  We always turn on O_NOFOLLOW
+ * for reasons described elsewhere.
+ */
+static int
+fs_oflags_dotu(int mode, int *aflags)
+{
+	int flags;
+#define	CONVERT(theirs, ours) \
+	do { \
+		if (mode & (theirs)) { \
+			mode &= ~(theirs); \
+			flags |= ours; \
+		} \
+	} while (0)
+
+	switch (mode & L9P_OACCMODE) {
+
+	case L9P_OREAD:
+	default:
+		flags = O_RDONLY;
+		break;
+
+	case L9P_OWRITE:
+		flags = O_WRONLY;
+		break;
+
+	case L9P_ORDWR:
+		flags = O_RDWR;
+		break;
+
+	case L9P_OEXEC:
+		if (mode & L9P_OTRUNC)
+			return (EINVAL);
+		flags = O_RDONLY;
+		break;
+	}
+
+	flags |= O_NOCTTY | O_NOFOLLOW;
+
+	CONVERT(L9P_OTRUNC, O_TRUNC);
+
+	/*
+	 * Now take away some flags locally:
+	 *   the access mode (already translated)
+	 *   ORCLOSE - caller only
+	 *   OCEXEC - makes no sense in server
+	 *   ODIRECT - not applicable here
+	 * If there are any flag bits left after this,
+	 * we were unable to translate them.  For now, let's
+	 * treat this as EINVAL so that we can catch problems.
+	 */
+	mode &= ~(L9P_OACCMODE | L9P_ORCLOSE | L9P_OCEXEC | L9P_ODIRECT);
+	if (mode != 0) {
+		L9P_LOG(L9P_INFO,
+		    "fs_oflags_dotu: untranslated bits: %#x",
+		    (unsigned)mode);
+		return (EINVAL);
+	}
+
+	*aflags = flags;
+	return (0);
+#undef CONVERT
+}
+
+/*
+ * Convert from 9P2000.L (Linux) open mode bits to O_* flags.
+ * See fs_oflags_dotu above.
+ *
+ * Linux currently does not have open-for-exec, but there is a
+ * proposal for it using O_PATH|O_NOFOLLOW, now handled here.
+ *
+ * We may eventually also set L9P_ORCLOSE for L_O_TMPFILE.
+ */
+static int
+fs_oflags_dotl(uint32_t l_mode, int *aflags, enum l9p_omode *ap9)
+{
+	int flags;
+	enum l9p_omode p9;
+#define	CLEAR(theirs)	l_mode &= ~(uint32_t)(theirs)
+#define	CONVERT(theirs, ours) \
+	do { \
+		if (l_mode & (theirs)) { \
+			CLEAR(theirs); \
+			flags |= ours; \
+		} \
+	} while (0)
+
+	/*
+	 * Linux O_RDONLY, O_WRONLY, O_RDWR (0,1,2) match BSD/MacOS.
+	 */
+	flags = l_mode & O_ACCMODE;
+	if (flags == 3)
+		return (EINVAL);
+	CLEAR(O_ACCMODE);
+
+	if ((l_mode & (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) ==
+		    (L9P_L_O_PATH | L9P_L_O_NOFOLLOW)) {
+		CLEAR(L9P_L_O_PATH | L9P_L_O_NOFOLLOW);
+		p9 = L9P_OEXEC;
+	} else {
+		/*
+		 * Slightly dirty, but same dirt, really, as
+		 * setting flags from l_mode & O_ACCMODE.
+		 */
+		p9 = (enum l9p_omode)flags;	/* slightly dirty */
+	}
+
+	/* turn L_O_TMPFILE into L9P_ORCLOSE in *p9? */
+	if (l_mode & L9P_L_O_TRUNC)
+		p9 |= L9P_OTRUNC;	/* but don't CLEAR yet */
+
+	flags |= O_NOCTTY | O_NOFOLLOW;
+
+	/*
+	 * L_O_CREAT seems to be noise, since we get separate open
+	 * and create.  But it is actually set sometimes.  We just
+	 * throw it out here; create ops must set it themselves and
+	 * open ops have no permissions bits and hence cannot create.
+	 *
+	 * L_O_EXCL does make sense on create ops, i.e., we can
+	 * take a create op with or without L_O_EXCL.  We pass that
+	 * through.
+	 */
+	CLEAR(L9P_L_O_CREAT);
+	CONVERT(L9P_L_O_EXCL, O_EXCL);
+	CONVERT(L9P_L_O_TRUNC, O_TRUNC);
+	CONVERT(L9P_L_O_DIRECTORY, O_DIRECTORY);
+	CONVERT(L9P_L_O_APPEND, O_APPEND);
+	CONVERT(L9P_L_O_NONBLOCK, O_NONBLOCK);
+
+	/*
+	 * Discard these as useless noise at our (server) end.
+	 * (NOATIME might be useful but we can only set it on a
+	 * per-mount basis.)
+	 */
+	CLEAR(L9P_L_O_CLOEXEC);
+	CLEAR(L9P_L_O_DIRECT);
+	CLEAR(L9P_L_O_DSYNC);
+	CLEAR(L9P_L_O_FASYNC);
+	CLEAR(L9P_L_O_LARGEFILE);
+	CLEAR(L9P_L_O_NOATIME);
+	CLEAR(L9P_L_O_NOCTTY);
+	CLEAR(L9P_L_O_NOFOLLOW);
+	CLEAR(L9P_L_O_SYNC);
+
+	if (l_mode != 0) {
+		L9P_LOG(L9P_INFO,
+		    "fs_oflags_dotl: untranslated bits: %#x",
+		    (unsigned)l_mode);
+		return (EINVAL);
+	}
+
+	*aflags = flags;
+	*ap9 = p9;
+	return (0);
+#undef CLEAR
+#undef CONVERT
+}
+
+static struct passwd *
+fs_getpwuid(struct fs_softc *sc, uid_t uid, struct r_pgdata *pg)
+{
+#if defined(WITH_CASPER)
+	return (r_cap_getpwuid(sc->fs_cappwd, uid, pg));
+#else
+	(void)sc;
+	return (r_getpwuid(uid, pg));
+#endif
+}
+
+static struct group *
+fs_getgrgid(struct fs_softc *sc, gid_t gid, struct r_pgdata *pg)
+{
+#if defined(WITH_CASPER)
+	return (r_cap_getgrgid(sc->fs_capgrp, gid, pg));
+#else
+	(void)sc;
+	return (r_getgrgid(gid, pg));
+#endif
+}
+
+/*
+ * Build full name of file by appending given name to directory name.
+ */
+static int
+fs_buildname(struct l9p_fid *dir, char *name, char *buf, size_t size)
+{
+	struct fs_fid *dirf = dir->lo_aux;
+	size_t dlen, nlen1;
+
+	assert(dirf != NULL);
+	dlen = strlen(dirf->ff_name);
+	nlen1 = strlen(name) + 1;	/* +1 for '\0' */
+	if (dlen + 1 + nlen1 > size)
+		return (ENAMETOOLONG);
+	memcpy(buf, dirf->ff_name, dlen);
+	buf[dlen] = '/';
+	memcpy(buf + dlen + 1, name, nlen1);
+	return (0);
+}
+
+/*
+ * Build parent name of file by splitting it off.  Return an error
+ * if the given fid represents the root, so that there is no such
+ * parent, or if the discovered parent is not a directory.
+ */
+static int
+fs_pdir(struct fs_softc *sc __unused, struct l9p_fid *fid, char *buf,
+    size_t size, struct stat *st)
+{
+	struct fs_fid *ff;
+	char *path;
+
+	ff = fid->lo_aux;
+	assert(ff != NULL);
+	path = ff->ff_name;
+	path = r_dirname(path, buf, size);
+	if (path == NULL)
+		return (ENAMETOOLONG);
+	if (fstatat(ff->ff_dirfd, path, st, AT_SYMLINK_NOFOLLOW) != 0)
+		return (errno);
+	if (!S_ISDIR(st->st_mode))
+		return (ENOTDIR);
+	return (0);
+}
+
+/*
+ * Like fs_buildname() but for adding a file name to a buffer
+ * already holding a directory name.  Essentially does
+ *     strcat(dbuf, "/");
+ *     strcat(dbuf, fname);
+ * but with size checking and an ENAMETOOLONG error as needed.
+ *
+ * (Think of the function name as "directory plus-equals file".)
+ */
+static int
+fs_dpf(char *dbuf, char *fname, size_t size)
+{
+	size_t dlen, nlen1;
+
+	dlen = strlen(dbuf);
+	nlen1 = strlen(fname) + 1;
+	if (dlen + 1 + nlen1 > size)
+		return (ENAMETOOLONG);
+	dbuf[dlen] = '/';
+	memcpy(dbuf + dlen + 1, fname, nlen1);
+	return (0);
+}
+
+/*
+ * Prepare to create a new directory entry (open with O_CREAT,
+ * mkdir, etc -- any operation that creates a new inode),
+ * operating in parent data <dir>, based on authinfo <ai> and
+ * effective gid <egid>.
+ *
+ * The new entity should be owned by user/group <*nuid, *ngid>,
+ * if it's really a new entity.  It will be a directory if isdir.
+ *
+ * Returns an error number if the entry should not be created
+ * (e.g., read-only file system or no permission to write in
+ * parent directory).  Always sets *nuid and *ngid on success:
+ * in the worst case, when there is no available ID, this will
+ * use the parent directory's IDs.  Fills in <*st> on success.
+ */
+static int
+fs_nde(struct fs_softc *sc, struct l9p_fid *dir, bool isdir, gid_t egid,
+    struct stat *st, uid_t *nuid, gid_t *ngid)
+{
+	struct fs_fid *dirf;
+	struct fs_authinfo *ai;
+	int32_t op;
+	int error;
+
+	if (sc->fs_readonly)
+		return (EROFS);
+	dirf = dir->lo_aux;
+	assert(dirf != NULL);
+	if (fstatat(dirf->ff_dirfd, dirf->ff_name, st,
+	    AT_SYMLINK_NOFOLLOW) != 0)
+		return (errno);
+	if (!S_ISDIR(st->st_mode))
+		return (ENOTDIR);
+	dirf = dir->lo_aux;
+	ai = dirf->ff_ai;
+	fillacl(dirf);
+	op = isdir ? L9P_ACE_ADD_SUBDIRECTORY : L9P_ACE_ADD_FILE;
+	error = check_access(op, dirf->ff_acl, st, NULL, NULL, ai, egid);
+	if (error)
+		return (EPERM);
+
+	*nuid = ai->ai_uid != (uid_t)-1 ? ai->ai_uid : st->st_uid;
+	*ngid = egid != (gid_t)-1 ? egid :
+	    ai->ai_ngids > 0 ?  ai->ai_gids[0] : st->st_gid;
+	return (0);
+}
+
+/*
+ * Allocate new open-file data structure to attach to a fid.
+ *
+ * The new file's authinfo is the same as the old one's, and
+ * we gain a reference.
+ */
+static struct fs_fid *
+open_fid(int dirfd, const char *path, struct fs_authinfo *ai, bool creating)
+{
+	struct fs_fid *ret;
+	uint32_t newcount;
+	int error;
+
+	ret = l9p_calloc(1, sizeof(*ret));
+	error = pthread_mutex_init(&ret->ff_mtx, NULL);
+	if (error) {
+		free(ret);
+		return (NULL);
+	}
+	ret->ff_fd = -1;
+	ret->ff_dirfd = dirfd;
+	ret->ff_name = strdup(path);
+	if (ret->ff_name == NULL) {
+		pthread_mutex_destroy(&ret->ff_mtx);
+		free(ret);
+		return (NULL);
+	}
+	pthread_mutex_lock(&ai->ai_mtx);
+	newcount = ++ai->ai_refcnt;
+	pthread_mutex_unlock(&ai->ai_mtx);
+	/*
+	 * If we just incremented the count to 1, we're the *first*
+	 * reference.  This is only allowed when creating the authinfo,
+	 * otherwise it means something has gone wrong.  This cannot
+	 * catch every bad (re)use of a freed authinfo but it may catch
+	 * a few.
+	 */
+	assert(newcount > 1 || creating);
+	L9P_LOG(L9P_DEBUG, "authinfo %p now used by %lu",
+	    (void *)ai, (u_long)newcount);
+	ret->ff_ai = ai;
+	return (ret);
+}
+
+static void
+dostat(struct fs_softc *sc, struct l9p_stat *s, char *name,
+    struct stat *buf, bool dotu)
+{
+	struct passwd *user;
+	struct group *group;
+
+	memset(s, 0, sizeof(struct l9p_stat));
+
+	generate_qid(buf, &s->qid);
+
+	s->type = 0;
+	s->dev = 0;
+	s->mode = buf->st_mode & 0777;
+
+	if (S_ISDIR(buf->st_mode))
+		s->mode |= L9P_DMDIR;
+
+	if (S_ISLNK(buf->st_mode) && dotu)
+		s->mode |= L9P_DMSYMLINK;
+
+	if (S_ISCHR(buf->st_mode) || S_ISBLK(buf->st_mode))
+		s->mode |= L9P_DMDEVICE;
+
+	if (S_ISSOCK(buf->st_mode))
+		s->mode |= L9P_DMSOCKET;
+
+	if (S_ISFIFO(buf->st_mode))
+		s->mode |= L9P_DMNAMEDPIPE;
+
+	s->atime = (uint32_t)buf->st_atime;
+	s->mtime = (uint32_t)buf->st_mtime;
+	s->length = (uint64_t)buf->st_size;
+
+	s->name = r_basename(name, NULL, 0);
+
+	if (!dotu) {
+		struct r_pgdata udata, gdata;
+
+		user = fs_getpwuid(sc, buf->st_uid, &udata);
+		group = fs_getgrgid(sc, buf->st_gid, &gdata);
+		s->uid = user != NULL ? strdup(user->pw_name) : NULL;
+		s->gid = group != NULL ? strdup(group->gr_name) : NULL;
+		s->muid = user != NULL ? strdup(user->pw_name) : NULL;
+		r_pgfree(&udata);
+		r_pgfree(&gdata);
+	} else {
+		/*
+		 * When using 9P2000.u, we don't need to bother about
+		 * providing user and group names in textual form.
+		 *
+		 * NB: if the asprintf()s fail, s->extension should
+		 * be unset so we can ignore these.
+		 */
+		s->n_uid = buf->st_uid;
+		s->n_gid = buf->st_gid;
+		s->n_muid = buf->st_uid;
+
+		if (S_ISLNK(buf->st_mode)) {
+			char target[MAXPATHLEN];
+			ssize_t ret = readlink(name, target, MAXPATHLEN);
+
+			if (ret < 0) {
+				s->extension = NULL;
+				return;
+			}
+
+			s->extension = strndup(target, (size_t)ret);
+		}
+
+		if (S_ISBLK(buf->st_mode)) {
+			asprintf(&s->extension, "b %d %d", major(buf->st_rdev),
+			    minor(buf->st_rdev));
+		}
+
+		if (S_ISCHR(buf->st_mode)) {
+			asprintf(&s->extension, "c %d %d", major(buf->st_rdev),
+			    minor(buf->st_rdev));
+		}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202004291624.03TGOXsf023532>