Merge pull request #2 from stv0g/virtio-9p
Updating to latest master & added documentation, lib9p as a git submodule
This commit is contained in:
commit
200277a234
26 changed files with 41 additions and 3647 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "lib9p"]
|
||||
path = lib9p
|
||||
url = https://github.com/jceel/lib9p.git
|
35
README.md
35
README.md
|
@ -18,9 +18,22 @@ Requirements
|
|||
* OS X 10.10.3 Yosemite or later
|
||||
* a 2010 or later Mac (i.e. a CPU that supports EPT)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
If you have homebrew, then simply:
|
||||
|
||||
$ brew update
|
||||
$ brew install --HEAD xhyve
|
||||
|
||||
The `--HEAD` in the brew command ensures that you always get the latest changes, even if the homebrew database is not yet updated. If for any reason you don't want that simply do `brew install xhyve` .
|
||||
|
||||
if not then:
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
$ git clone --recursive https://github.com/mist64/xhyve
|
||||
$ cd xhyve
|
||||
$ make
|
||||
|
||||
The resulting binary will be in build/xhyve
|
||||
|
@ -57,7 +70,7 @@ It exposes the following peripherals to virtual machines:
|
|||
|
||||
Notably absent are sound, USB, HID and any kind of graphics support. With a focus on server virtualization this is not strictly a requirement. bhyve may gain desktop virtualization capabilities in the future but this doesn't seem to be a priority.
|
||||
|
||||
Unlike QEMU, byhve also currently lacks any kind of guest-side firmware (QEMU uses the GPL3 [SeaBIOS](http://www.seabios.org)), but aims to provide a compatible [OVMF EFI](http://www.linux-kvm.org/page/OVMF) in the near future. It does however provide ACPI, SMBIOS and MP Tables.
|
||||
Unlike QEMU, bhyve also currently lacks any kind of guest-side firmware (QEMU uses the GPL3 [SeaBIOS](http://www.seabios.org)), but aims to provide a compatible [OVMF EFI](http://www.linux-kvm.org/page/OVMF) in the near future. It does however provide ACPI, SMBIOS and MP Tables.
|
||||
|
||||
bhyve architecture
|
||||
------------------
|
||||
|
@ -140,7 +153,7 @@ xhyve architecture
|
|||
------------------------------┼------------------------------
|
||||
|syscall xnu kernel
|
||||
V
|
||||
|
||||
|
||||
VMX host
|
||||
VMX nested paging
|
||||
|
||||
|
@ -169,6 +182,22 @@ instead of:
|
|||
|
||||
Where *X* is your tap device, i.e. */dev/tapX*.
|
||||
|
||||
File Sharing
|
||||
------
|
||||
You can setup shared folders between OS X and your guest by using the `virtio-9p` device.
|
||||
9P / VirtFS is a shared FS protocol introduced by Bell's Plan 9 OS.
|
||||
More information is available in the [KVM wiki](http://www.linux-kvm.org/page/9p_virtio).
|
||||
|
||||
Adding a VirtFS device to your VM:
|
||||
|
||||
$ xhyve -s 5,virtio-9p,hostshare=/Users/example/shared,ro ...
|
||||
|
||||
Inside the Linux VM:
|
||||
|
||||
$ mount -t 9p -o trans=virtio,version=9p2000.L hostshare /tmp/host_files
|
||||
|
||||
The `hostshare` identifier can be changed to support multiple mounts.
|
||||
|
||||
Issues
|
||||
------
|
||||
If you are, or were, running any version of VirtualBox, prior to 4.3.30 or 5.0,
|
||||
|
|
1
lib9p
Submodule
1
lib9p
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit ddfdba40793f4bd2e988d4832cfadbf71ab7d024
|
33
lib9p/.gitignore
vendored
33
lib9p/.gitignore
vendored
|
@ -1,33 +0,0 @@
|
|||
# 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/
|
|
@ -1,47 +0,0 @@
|
|||
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.
|
|
@ -1,48 +0,0 @@
|
|||
CFLAGS := \
|
||||
-Weverything \
|
||||
-Wno-padded \
|
||||
-Wno-gnu-zero-variadic-macro-arguments \
|
||||
-Wno-format-nonliteral \
|
||||
-Werror \
|
||||
-g \
|
||||
-O0
|
||||
|
||||
LIB_SRCS := \
|
||||
pack.c \
|
||||
connection.c \
|
||||
request.c \
|
||||
log.c \
|
||||
hashtable.c \
|
||||
utils.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 $@
|
||||
|
||||
$(SERVER): $(SERVER_OBJS) $(LIB)
|
||||
cc $< -o build/$(SERVER) -L. -l9p
|
||||
|
||||
clean:
|
||||
rm -rf build
|
||||
|
||||
build:
|
||||
mkdir build
|
||||
mkdir build/sbuf
|
||||
mkdir build/transport
|
||||
mkdir build/backend
|
||||
|
||||
build/%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
|
@ -1,16 +0,0 @@
|
|||
LIB= 9p
|
||||
SHLIB_MAJOR= 1
|
||||
SRCS= pack.c \
|
||||
connection.c \
|
||||
request.c log.c \
|
||||
hashtable.c \
|
||||
utils.c \
|
||||
transport/socket.c \
|
||||
backend/fs.c
|
||||
|
||||
INCS= lib9p.h
|
||||
CFLAGS= -g -O0
|
||||
|
||||
LIBADD= sbuf
|
||||
|
||||
.include <bsd.lib.mk>
|
|
@ -1,770 +0,0 @@
|
|||
/*
|
||||
* 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/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 <sys/socket.h>
|
||||
#include "../lib9p.h"
|
||||
#include "../lib9p_impl.h"
|
||||
#include "../log.h"
|
||||
|
||||
static struct openfile *open_fid(const char *);
|
||||
static void dostat(struct l9p_stat *, char *, struct stat *, bool dotu);
|
||||
static void generate_qid(struct stat *, struct l9p_qid *);
|
||||
static void fs_attach(void *, struct l9p_request *);
|
||||
static void fs_clunk(void *, struct l9p_request *);
|
||||
static void fs_create(void *, struct l9p_request *);
|
||||
static void fs_flush(void *, struct l9p_request *);
|
||||
static void fs_open(void *, struct l9p_request *);
|
||||
static void fs_read(void *, struct l9p_request *);
|
||||
static void fs_remove(void *, struct l9p_request *);
|
||||
static void fs_stat(void *, struct l9p_request *);
|
||||
static void fs_walk(void *, struct l9p_request *);
|
||||
static void fs_write(void *, struct l9p_request *);
|
||||
static void fs_wstat(void *, struct l9p_request *);
|
||||
static void fs_freefid(void *softc, struct l9p_openfile *f);
|
||||
|
||||
struct fs_softc
|
||||
{
|
||||
const char *fs_rootpath;
|
||||
bool fs_readonly;
|
||||
TAILQ_HEAD(, fs_tree) fs_auxtrees;
|
||||
};
|
||||
|
||||
struct fs_tree
|
||||
{
|
||||
const char *fst_name;
|
||||
const char *fst_path;
|
||||
bool fst_readonly;
|
||||
TAILQ_ENTRY(fs_tree) fst_link;
|
||||
};
|
||||
|
||||
struct openfile
|
||||
{
|
||||
DIR *dir;
|
||||
int fd;
|
||||
char *name;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
};
|
||||
|
||||
static struct openfile *
|
||||
open_fid(const char *path)
|
||||
{
|
||||
struct openfile *ret;
|
||||
|
||||
ret = l9p_calloc(1, sizeof(*ret));
|
||||
ret->fd = -1;
|
||||
ret->name = strdup(path);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
dostat(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;
|
||||
|
||||
/* XXX: not thread safe */
|
||||
s->name = strdup(basename(name));
|
||||
|
||||
if (!dotu) {
|
||||
user = getpwuid(buf->st_uid);
|
||||
group = getgrgid(buf->st_gid);
|
||||
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;
|
||||
} else {
|
||||
/*
|
||||
* When using 9P2000.u, we don't need to bother about
|
||||
* providing user and group names in textual form.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
generate_qid(struct stat *buf, struct l9p_qid *qid)
|
||||
{
|
||||
qid->path = buf->st_ino;
|
||||
qid->version = 0;
|
||||
|
||||
if (S_ISREG(buf->st_mode))
|
||||
qid->type |= L9P_QTFILE;
|
||||
|
||||
if (S_ISDIR(buf->st_mode))
|
||||
qid->type |= L9P_QTDIR;
|
||||
|
||||
if (S_ISLNK(buf->st_mode))
|
||||
qid->type |= L9P_QTSYMLINK;
|
||||
}
|
||||
|
||||
static bool
|
||||
check_access(struct stat *st, uid_t uid, int amode)
|
||||
{
|
||||
struct passwd *pwd;
|
||||
int groups[NGROUPS_MAX];
|
||||
int ngroups = NGROUPS_MAX;
|
||||
int i;
|
||||
|
||||
if (uid == 0)
|
||||
return (true);
|
||||
|
||||
if (st->st_uid == uid) {
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IRUSR)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWUSR)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXUSR)
|
||||
return (true);
|
||||
}
|
||||
|
||||
/* Check for "other" access */
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IROTH)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWOTH)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXOTH)
|
||||
return (true);
|
||||
|
||||
/* Check for group access */
|
||||
pwd = getpwuid(uid);
|
||||
getgrouplist(pwd->pw_name, (int)pwd->pw_gid, groups, &ngroups);
|
||||
|
||||
for (i = 0; i < ngroups; i++) {
|
||||
if (st->st_gid == (gid_t)groups[i]) {
|
||||
if (amode == L9P_OREAD && st->st_mode & S_IRGRP)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OWRITE && st->st_mode & S_IWGRP)
|
||||
return (true);
|
||||
|
||||
if (amode == L9P_OEXEC && st->st_mode & S_IXGRP)
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_attach(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = (struct fs_softc *)softc;
|
||||
struct openfile *file;
|
||||
struct passwd *pwd;
|
||||
uid_t uid;
|
||||
|
||||
assert(req->lr_fid != NULL);
|
||||
|
||||
file = open_fid(sc->fs_rootpath);
|
||||
req->lr_fid->lo_qid.type = L9P_QTDIR;
|
||||
req->lr_fid->lo_qid.path = (uintptr_t)req->lr_fid;
|
||||
req->lr_fid->lo_aux = file;
|
||||
req->lr_resp.rattach.qid = req->lr_fid->lo_qid;
|
||||
|
||||
uid = req->lr_req.tattach.n_uname;
|
||||
if (req->lr_conn->lc_version >= L9P_2000U && uid != (uid_t)-1)
|
||||
pwd = getpwuid(uid);
|
||||
else
|
||||
pwd = getpwnam(req->lr_req.tattach.uname);
|
||||
|
||||
if (pwd == NULL) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
file->uid = pwd->pw_uid;
|
||||
file->gid = pwd->pw_gid;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_clunk(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct openfile *file;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
if (file->dir) {
|
||||
closedir(file->dir);
|
||||
file->dir = NULL;
|
||||
} else if (file->fd != -1) {
|
||||
close(file->fd);
|
||||
file->fd = -1;
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_create(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct stat st;
|
||||
char *newname;
|
||||
mode_t mode = req->lr_req.tcreate.perm & 0777;
|
||||
|
||||
assert(file != NULL);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
asprintf(&newname, "%s/%s", file->name, req->lr_req.tcreate.name);
|
||||
|
||||
if (stat(file->name, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_access(&st, file->uid, L9P_OWRITE)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->lr_req.tcreate.perm & L9P_DMDIR)
|
||||
mkdir(newname, mode);
|
||||
else if (req->lr_req.tcreate.perm & L9P_DMSYMLINK) {
|
||||
if (symlink(req->lr_req.tcreate.extension, newname) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
} else if (req->lr_req.tcreate.perm & L9P_DMNAMEDPIPE) {
|
||||
if (mkfifo(newname, mode) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
} else if (req->lr_req.tcreate.perm & L9P_DMSOCKET) {
|
||||
struct sockaddr_un sun;
|
||||
int s = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
|
||||
if (s < 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
sun.sun_family = AF_UNIX;
|
||||
sun.sun_len = sizeof(struct sockaddr_un);
|
||||
strncpy(sun.sun_path, newname, sizeof(sun.sun_path));
|
||||
|
||||
if (bind(s, (struct sockaddr *)&sun, sun.sun_len) < 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (close(s) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
} else if (req->lr_req.tcreate.perm & L9P_DMDEVICE) {
|
||||
char type;
|
||||
int major, minor;
|
||||
|
||||
if (sscanf(req->lr_req.tcreate.extension, "%c %u %u",
|
||||
&type, &major, &minor) < 2) {
|
||||
l9p_respond(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case 'b':
|
||||
if (mknod(newname, S_IFBLK | mode,
|
||||
makedev(major, minor)) != 0)
|
||||
{
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'c':
|
||||
if (mknod(newname, S_IFCHR | mode,
|
||||
makedev(major, minor)) != 0)
|
||||
{
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
l9p_respond(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
file->fd = open(newname,
|
||||
O_CREAT | O_TRUNC | req->lr_req.tcreate.mode,
|
||||
mode);
|
||||
}
|
||||
|
||||
if (lchown(newname, file->uid, file->gid) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (stat(newname, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
generate_qid(&st, &req->lr_resp.rcreate.qid);
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_flush(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
|
||||
/* XXX: not used because this transport is synchronous */
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_open(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct stat st;
|
||||
|
||||
assert(file != NULL);
|
||||
|
||||
if (stat(file->name, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_access(&st, file->uid, req->lr_req.topen.mode)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode))
|
||||
file->dir = opendir(file->name);
|
||||
else {
|
||||
file->fd = open(file->name, req->lr_req.topen.mode);
|
||||
if (file->fd < 0) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
generate_qid(&st, &req->lr_resp.ropen.qid);
|
||||
|
||||
req->lr_resp.ropen.iounit = conn->lc_max_io_size;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_read(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct openfile *file;
|
||||
struct l9p_stat l9stat;
|
||||
bool dotu = req->lr_conn->lc_version >= L9P_2000U;
|
||||
ssize_t ret;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
if (file->dir != NULL) {
|
||||
struct dirent *d;
|
||||
struct stat st;
|
||||
|
||||
for (;;) {
|
||||
d = readdir(file->dir);
|
||||
if (d) {
|
||||
lstat(d->d_name, &st);
|
||||
dostat(&l9stat, d->d_name, &st, dotu);
|
||||
if (l9p_pack_stat(req, &l9stat) != 0) {
|
||||
seekdir(file->dir, -1);
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
size_t niov = l9p_truncate_iov(req->lr_data_iov,
|
||||
req->lr_data_niov, req->lr_req.io.count);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
ret = preadv(file->fd, req->lr_data_iov, niov,
|
||||
req->lr_req.io.offset);
|
||||
#else
|
||||
/* XXX: not thread safe, should really use aio_listio. */
|
||||
if (lseek(file->fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0)
|
||||
{
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = (uint32_t)readv(file->fd, req->lr_data_iov, (int)niov);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
req->lr_resp.io.count = (uint32_t)ret;
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_remove(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
struct stat st;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lstat(file->name, &st) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!check_access(&st, file->uid, L9P_OWRITE)) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
if (rmdir(file->name) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (unlink(file->name) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_stat(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
struct openfile *file;
|
||||
struct stat st;
|
||||
bool dotu = req->lr_conn->lc_version >= L9P_2000U;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file);
|
||||
|
||||
lstat(file->name, &st);
|
||||
dostat(&req->lr_resp.rstat.stat, file->name, &st, dotu);
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_walk(void *softc __unused, struct l9p_request *req)
|
||||
{
|
||||
uint16_t i;
|
||||
struct stat buf;
|
||||
struct openfile *file = req->lr_fid->lo_aux;
|
||||
struct openfile *newfile;
|
||||
char name[MAXPATHLEN];
|
||||
|
||||
strcpy(name, file->name);
|
||||
|
||||
for (i = 0; i < req->lr_req.twalk.nwname; i++) {
|
||||
strcat(name, "/");
|
||||
strcat(name, req->lr_req.twalk.wname[i]);
|
||||
if (lstat(name, &buf) < 0){
|
||||
l9p_respond(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
generate_qid(&buf, &req->lr_resp.rwalk.wqid[i]);
|
||||
}
|
||||
|
||||
newfile = open_fid(name);
|
||||
newfile->uid = file->uid;
|
||||
newfile->gid = file->gid;
|
||||
req->lr_newfid->lo_aux = newfile;
|
||||
req->lr_resp.rwalk.nwqid = i;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_write(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
ssize_t ret;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t niov = l9p_truncate_iov(req->lr_data_iov,
|
||||
req->lr_data_niov, req->lr_req.io.count);
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
ret = pwritev(file->fd, req->lr_data_iov, niov,
|
||||
req->lr_req.io.offset);
|
||||
#else
|
||||
/* XXX: not thread safe, should really use aio_listio. */
|
||||
if (lseek(file->fd, (off_t)req->lr_req.io.offset, SEEK_SET) < 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = writev(file->fd, req->lr_data_iov,
|
||||
(int)niov);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
|
||||
req->lr_resp.io.count = (uint32_t)ret;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_wstat(void *softc, struct l9p_request *req)
|
||||
{
|
||||
struct fs_softc *sc = softc;
|
||||
struct openfile *file;
|
||||
struct l9p_stat *l9stat = &req->lr_req.twstat.stat;
|
||||
|
||||
file = req->lr_fid->lo_aux;
|
||||
assert(file != NULL);
|
||||
|
||||
/*
|
||||
* XXX:
|
||||
*
|
||||
* stat(9P) sez:
|
||||
*
|
||||
* Either all the changes in wstat request happen, or none of them
|
||||
* does: if the request succeeds, all changes were made; if it fails,
|
||||
* none were.
|
||||
*
|
||||
* Atomicity is clearly missing in current implementation.
|
||||
*/
|
||||
|
||||
if (sc->fs_readonly) {
|
||||
l9p_respond(req, EROFS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l9stat->atime != (uint32_t)~0) {
|
||||
/* XXX: not implemented, ignore */
|
||||
}
|
||||
|
||||
if (l9stat->mtime != (uint32_t)~0) {
|
||||
/* XXX: not implemented, ignore */
|
||||
}
|
||||
|
||||
if (l9stat->dev != (uint32_t)~0) {
|
||||
l9p_respond(req, EPERM);
|
||||
return;
|
||||
}
|
||||
|
||||
if (l9stat->length != (uint64_t)~0) {
|
||||
if (file->dir != NULL) {
|
||||
l9p_respond(req, EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (truncate(file->name, (off_t)l9stat->length) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (req->lr_conn->lc_version >= L9P_2000U) {
|
||||
if (lchown(file->name, l9stat->n_uid, l9stat->n_gid) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (l9stat->mode != (uint32_t)~0) {
|
||||
if (chmod(file->name, l9stat->mode & 0777) != 0) {
|
||||
l9p_respond(req, errno);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(l9stat->name) > 0) {
|
||||
/* XXX: not thread safe */
|
||||
char *dir = dirname(file->name);
|
||||
char *newname;
|
||||
|
||||
asprintf(&newname, "%s/%s", dir, l9stat->name);
|
||||
rename(file->name, newname);
|
||||
|
||||
free(newname);
|
||||
}
|
||||
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
fs_freefid(void *softc __unused, struct l9p_openfile *fid)
|
||||
{
|
||||
struct openfile *f = fid->lo_aux;
|
||||
|
||||
if (f == NULL) {
|
||||
/* Nothing to do here */
|
||||
return;
|
||||
}
|
||||
|
||||
if (f->fd != -1)
|
||||
close(f->fd);
|
||||
|
||||
if (f->dir)
|
||||
closedir(f->dir);
|
||||
|
||||
free(f->name);
|
||||
free(f);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_backend_fs_init(struct l9p_backend **backendp, const char *root)
|
||||
{
|
||||
struct l9p_backend *backend;
|
||||
struct fs_softc *sc;
|
||||
|
||||
backend = l9p_malloc(sizeof(*backend));
|
||||
backend->attach = fs_attach;
|
||||
backend->clunk = fs_clunk;
|
||||
backend->create = fs_create;
|
||||
backend->flush = fs_flush;
|
||||
backend->open = fs_open;
|
||||
backend->read = fs_read;
|
||||
backend->remove = fs_remove;
|
||||
backend->stat = fs_stat;
|
||||
backend->walk = fs_walk;
|
||||
backend->write = fs_write;
|
||||
backend->wstat = fs_wstat;
|
||||
backend->freefid = fs_freefid;
|
||||
|
||||
sc = l9p_malloc(sizeof(*sc));
|
||||
sc->fs_rootpath = strdup(root);
|
||||
sc->fs_readonly = false;
|
||||
backend->softc = sc;
|
||||
|
||||
setpassent(1);
|
||||
|
||||
*backendp = backend;
|
||||
return (0);
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/queue.h>
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
#include "hashtable.h"
|
||||
#include "log.h"
|
||||
|
||||
int
|
||||
l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend)
|
||||
{
|
||||
struct l9p_server *server;
|
||||
|
||||
server = l9p_calloc(1, sizeof (*server));
|
||||
server->ls_max_version = L9P_2000U;
|
||||
server->ls_backend = backend;
|
||||
LIST_INIT(&server->ls_conns);
|
||||
|
||||
*serverp = server;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn)
|
||||
{
|
||||
struct l9p_connection *newconn;
|
||||
|
||||
assert(server != NULL);
|
||||
assert(conn != NULL);
|
||||
|
||||
newconn = l9p_calloc(1, sizeof (*newconn));
|
||||
newconn->lc_server = server;
|
||||
newconn->lc_msize = L9P_DEFAULT_MSIZE;
|
||||
ht_init(&newconn->lc_files, 100);
|
||||
ht_init(&newconn->lc_requests, 100);
|
||||
LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link);
|
||||
*conn = newconn;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_free(struct l9p_connection *conn)
|
||||
{
|
||||
|
||||
LIST_REMOVE(conn, lc_link);
|
||||
free(conn);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_on_send_response(struct l9p_connection *conn,
|
||||
l9p_send_response_t cb, void *aux)
|
||||
{
|
||||
|
||||
conn->lc_send_response = cb;
|
||||
conn->lc_send_response_aux = aux;
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_on_get_response_buffer(struct l9p_connection *conn,
|
||||
l9p_get_response_buffer_t cb, void *aux)
|
||||
{
|
||||
|
||||
conn->lc_get_response_buffer = cb;
|
||||
conn->lc_get_response_buffer_aux = aux;
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
|
||||
const size_t niov, void *aux)
|
||||
{
|
||||
struct l9p_request *req;
|
||||
|
||||
req = l9p_calloc(1, sizeof (struct l9p_request));
|
||||
req->lr_aux = aux;
|
||||
req->lr_conn = conn;
|
||||
ht_add(&conn->lc_requests, req->lr_req.hdr.tag, req);
|
||||
|
||||
req->lr_req_msg.lm_mode = L9P_UNPACK;
|
||||
req->lr_req_msg.lm_niov = niov;
|
||||
memcpy(req->lr_req_msg.lm_iov, iov, sizeof (struct iovec) * niov);
|
||||
|
||||
req->lr_resp_msg.lm_mode = L9P_PACK;
|
||||
|
||||
if (l9p_pufcall(&req->lr_req_msg, &req->lr_req, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot unpack received message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (conn->lc_get_response_buffer(req, req->lr_resp_msg.lm_iov,
|
||||
&req->lr_resp_msg.lm_niov, conn->lc_get_response_buffer_aux) != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot obtain buffers for response");
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_dispatch_request(req);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_close(struct l9p_connection *conn)
|
||||
{
|
||||
struct ht_iter iter;
|
||||
struct l9p_openfile *fid;
|
||||
struct l9p_request *req;
|
||||
|
||||
/* Drain pending requests (if any) */
|
||||
ht_iter(&conn->lc_requests, &iter);
|
||||
while ((req = ht_next(&iter)) != NULL) {
|
||||
l9p_respond(req, EINTR);
|
||||
ht_remove_at_iter(&iter);
|
||||
}
|
||||
|
||||
/* Close opened files (if any) */
|
||||
ht_iter(&conn->lc_files, &iter);
|
||||
while ((fid = ht_next(&iter)) != NULL) {
|
||||
conn->lc_server->ls_backend->freefid(
|
||||
conn->lc_server->ls_backend->softc, fid);
|
||||
ht_remove_at_iter(&iter);
|
||||
}
|
||||
|
||||
ht_destroy(&conn->lc_requests);
|
||||
ht_destroy(&conn->lc_files);
|
||||
}
|
||||
|
||||
struct l9p_openfile *
|
||||
l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid)
|
||||
{
|
||||
struct l9p_openfile *file;
|
||||
|
||||
file = l9p_calloc(1, sizeof (struct l9p_openfile));
|
||||
file->lo_fid = fid;
|
||||
file->lo_conn = conn;
|
||||
if (ht_add(&conn->lc_files, fid, file) != 0) {
|
||||
free(file);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (file);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_openfile *fid)
|
||||
{
|
||||
|
||||
conn->lc_server->ls_backend->freefid(conn->lc_server->ls_backend->softc,
|
||||
fid);
|
||||
|
||||
ht_remove(&conn->lc_files, fid->lo_fid);
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <err.h>
|
||||
#include "../lib9p.h"
|
||||
#include "../transport/socket.h"
|
||||
#include "../backend/fs.h"
|
||||
|
||||
int
|
||||
main(int argc, const char *argv[])
|
||||
{
|
||||
struct l9p_backend *fs_backend;
|
||||
struct l9p_server *server;
|
||||
|
||||
if (argc < 2)
|
||||
errx(1, "Usage: server <path>");
|
||||
|
||||
if (l9p_backend_fs_init(&fs_backend, argv[1]) != 0)
|
||||
err(1, "cannot init backend");
|
||||
|
||||
if (l9p_server_init(&server, fs_backend) != 0)
|
||||
err(1, "cannot create server");
|
||||
|
||||
server->ls_max_version = L9P_2000U;
|
||||
l9p_start_server(server, "0.0.0.0", "564");
|
||||
}
|
236
lib9p/fcall.h
236
lib9p/fcall.h
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
* 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>
|
||||
*/
|
||||
|
||||
#ifndef LIB9P_FCALL_H
|
||||
#define LIB9P_FCALL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define L9P_MAX_WELEM 256
|
||||
|
||||
enum l9p_ftype {
|
||||
L9P_TVERSION = 100,
|
||||
L9P_RVERSION,
|
||||
L9P_TAUTH = 102,
|
||||
L9P_RAUTH,
|
||||
L9P_TATTACH = 104,
|
||||
L9P_RATTACH,
|
||||
L9P_TERROR = 106, /* illegal */
|
||||
L9P_RERROR,
|
||||
L9P_TFLUSH = 108,
|
||||
L9P_RFLUSH,
|
||||
L9P_TWALK = 110,
|
||||
L9P_RWALK,
|
||||
L9P_TOPEN = 112,
|
||||
L9P_ROPEN,
|
||||
L9P_TCREATE = 114,
|
||||
L9P_RCREATE,
|
||||
L9P_TREAD = 116,
|
||||
L9P_RREAD,
|
||||
L9P_TWRITE = 118,
|
||||
L9P_RWRITE,
|
||||
L9P_TCLUNK = 120,
|
||||
L9P_RCLUNK,
|
||||
L9P_TREMOVE = 122,
|
||||
L9P_RREMOVE,
|
||||
L9P_TSTAT = 124,
|
||||
L9P_RSTAT,
|
||||
L9P_TWSTAT = 126,
|
||||
L9P_RWSTAT,
|
||||
};
|
||||
|
||||
enum l9p_qid_type {
|
||||
L9P_QTDIR = 0x80, /* type bit for directories */
|
||||
L9P_QTAPPEND = 0x40, /* type bit for append only files */
|
||||
L9P_QTEXCL = 0x20, /* type bit for exclusive use files */
|
||||
L9P_QTMOUNT = 0x10, /* type bit for mounted channel */
|
||||
L9P_QTAUTH = 0x08, /* type bit for authentication file */
|
||||
L9P_QTTMP = 0x04, /* type bit for non-backed-up file */
|
||||
L9P_QTSYMLINK = 0x02, /* type bit for symbolic link */
|
||||
L9P_QTFILE = 0x00 /* type bits for plain file */
|
||||
};
|
||||
|
||||
#define L9P_DMDIR 0x80000000
|
||||
enum {
|
||||
L9P_DMAPPEND = 0x40000000,
|
||||
L9P_DMEXCL = 0x20000000,
|
||||
L9P_DMMOUNT = 0x10000000,
|
||||
L9P_DMAUTH = 0x08000000,
|
||||
L9P_DMTMP = 0x04000000,
|
||||
L9P_DMSYMLINK = 0x02000000,
|
||||
/* 9P2000.u extensions */
|
||||
L9P_DMDEVICE = 0x00800000,
|
||||
L9P_DMNAMEDPIPE = 0x00200000,
|
||||
L9P_DMSOCKET = 0x00100000,
|
||||
L9P_DMSETUID = 0x00080000,
|
||||
L9P_DMSETGID = 0x00040000,
|
||||
};
|
||||
|
||||
enum {
|
||||
L9P_OREAD = 0, /* open for read */
|
||||
L9P_OWRITE = 1, /* write */
|
||||
L9P_ORDWR = 2, /* read and write */
|
||||
L9P_OEXEC = 3, /* execute, == read but check execute permission */
|
||||
L9P_OTRUNC = 16, /* or'ed in (except for exec), truncate file first */
|
||||
L9P_OCEXEC = 32, /* or'ed in, close on exec */
|
||||
L9P_ORCLOSE = 64, /* or'ed in, remove on close */
|
||||
L9P_ODIRECT = 128, /* or'ed in, direct access */
|
||||
L9P_ONONBLOCK = 256, /* or'ed in, non-blocking call */
|
||||
L9P_OEXCL = 0x1000, /* or'ed in, exclusive use (create only) */
|
||||
L9P_OLOCK = 0x2000, /* or'ed in, lock after opening */
|
||||
L9P_OAPPEND = 0x4000 /* or'ed in, append only */
|
||||
};
|
||||
|
||||
struct l9p_hdr {
|
||||
uint8_t type;
|
||||
uint16_t tag;
|
||||
uint32_t fid;
|
||||
};
|
||||
|
||||
struct l9p_qid {
|
||||
enum l9p_qid_type type;
|
||||
uint32_t version;
|
||||
uint64_t path;
|
||||
};
|
||||
|
||||
struct l9p_stat {
|
||||
uint16_t type;
|
||||
uint32_t dev;
|
||||
struct l9p_qid qid;
|
||||
uint32_t mode;
|
||||
uint32_t atime;
|
||||
uint32_t mtime;
|
||||
uint64_t length;
|
||||
char *name;
|
||||
char *uid;
|
||||
char *gid;
|
||||
char *muid;
|
||||
char *extension;
|
||||
uid_t n_uid;
|
||||
gid_t n_gid;
|
||||
uid_t n_muid;
|
||||
};
|
||||
|
||||
struct l9p_f_version {
|
||||
struct l9p_hdr hdr;
|
||||
uint32_t msize;
|
||||
char *version;
|
||||
};
|
||||
|
||||
struct l9p_f_tflush {
|
||||
struct l9p_hdr hdr;
|
||||
uint16_t oldtag;
|
||||
};
|
||||
|
||||
struct l9p_f_error {
|
||||
struct l9p_hdr hdr;
|
||||
char *ename;
|
||||
uint32_t errnum;
|
||||
};
|
||||
|
||||
struct l9p_f_ropen {
|
||||
struct l9p_hdr hdr;
|
||||
struct l9p_qid qid;
|
||||
uint32_t iounit;
|
||||
};
|
||||
|
||||
struct l9p_f_rauth {
|
||||
struct l9p_hdr hdr;
|
||||
struct l9p_qid aqid;
|
||||
};
|
||||
|
||||
struct l9p_f_attach {
|
||||
struct l9p_hdr hdr;
|
||||
uint32_t afid;
|
||||
char *uname;
|
||||
char *aname;
|
||||
uid_t n_uname;
|
||||
};
|
||||
|
||||
struct l9p_f_tcreate {
|
||||
struct l9p_hdr hdr;
|
||||
uint32_t perm;
|
||||
char *name;
|
||||
uint8_t mode; /* +Topen */
|
||||
char *extension;
|
||||
};
|
||||
|
||||
struct l9p_f_twalk {
|
||||
struct l9p_hdr hdr;
|
||||
uint32_t newfid;
|
||||
uint16_t nwname;
|
||||
char *wname[L9P_MAX_WELEM];
|
||||
};
|
||||
|
||||
struct l9p_f_rwalk {
|
||||
struct l9p_hdr hdr;
|
||||
uint16_t nwqid;
|
||||
struct l9p_qid wqid[L9P_MAX_WELEM];
|
||||
};
|
||||
|
||||
struct l9p_f_io {
|
||||
struct l9p_hdr hdr;
|
||||
uint64_t offset; /* Tread, Twrite */
|
||||
uint32_t count; /* Tread, Twrite, Rread */
|
||||
char *data; /* Twrite, Rread */
|
||||
};
|
||||
|
||||
struct l9p_f_rstat {
|
||||
struct l9p_hdr hdr;
|
||||
struct l9p_stat stat;
|
||||
};
|
||||
|
||||
struct l9p_f_twstat {
|
||||
struct l9p_hdr hdr;
|
||||
struct l9p_stat stat;
|
||||
};
|
||||
|
||||
union l9p_fcall {
|
||||
struct l9p_hdr hdr;
|
||||
struct l9p_f_version version;
|
||||
struct l9p_f_tflush tflush;
|
||||
struct l9p_f_ropen ropen;
|
||||
struct l9p_f_ropen rcreate;
|
||||
struct l9p_f_ropen rattach;
|
||||
struct l9p_f_error error;
|
||||
struct l9p_f_rauth rauth;
|
||||
struct l9p_f_attach tattach;
|
||||
struct l9p_f_attach tauth;
|
||||
struct l9p_f_tcreate tcreate;
|
||||
struct l9p_f_tcreate topen;
|
||||
struct l9p_f_twalk twalk;
|
||||
struct l9p_f_rwalk rwalk;
|
||||
struct l9p_f_twstat twstat;
|
||||
struct l9p_f_rstat rstat;
|
||||
struct l9p_f_io io;
|
||||
};
|
||||
|
||||
#endif /* LIB9P_FCALL_H */
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include "lib9p_impl.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
void
|
||||
ht_init(struct ht *h, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
memset(h, 0, sizeof(struct ht));
|
||||
h->ht_nentries = size;
|
||||
h->ht_entries = l9p_calloc(size, sizeof(struct ht_entry));
|
||||
|
||||
for (i = 0; i < size; i++)
|
||||
TAILQ_INIT(&h->ht_entries[i].hte_items);
|
||||
}
|
||||
|
||||
void
|
||||
ht_destroy(struct ht *h)
|
||||
{
|
||||
struct ht_entry *he;
|
||||
struct ht_item *hi;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < h->ht_nentries; i++) {
|
||||
he = &h->ht_entries[i];
|
||||
hi = TAILQ_FIRST(&he->hte_items);
|
||||
|
||||
while ((hi = TAILQ_NEXT(hi, hti_link)) != NULL)
|
||||
TAILQ_REMOVE(&he->hte_items, hi, hti_link);
|
||||
}
|
||||
|
||||
free(h->ht_entries);
|
||||
free(h);
|
||||
}
|
||||
|
||||
void *
|
||||
ht_find(struct ht *h, uint32_t hash)
|
||||
{
|
||||
struct ht_entry *entry;
|
||||
struct ht_item *item;
|
||||
|
||||
entry = &h->ht_entries[hash % h->ht_nentries];
|
||||
|
||||
TAILQ_FOREACH(item, &entry->hte_items, hti_link) {
|
||||
if (item->hti_hash == hash)
|
||||
return (item->hti_data);
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
ht_add(struct ht *h, uint32_t hash, void *value)
|
||||
{
|
||||
struct ht_entry *entry;
|
||||
struct ht_item *item;
|
||||
|
||||
entry = &h->ht_entries[hash % h->ht_nentries];
|
||||
|
||||
TAILQ_FOREACH(item, &entry->hte_items, hti_link) {
|
||||
if (item->hti_hash == hash) {
|
||||
errno = EEXIST;
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
item = l9p_calloc(1, sizeof(struct ht_item));
|
||||
item->hti_hash = hash;
|
||||
item->hti_data = value;
|
||||
TAILQ_INSERT_TAIL(&entry->hte_items, item, hti_link);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ht_remove(struct ht *h, uint32_t hash)
|
||||
{
|
||||
struct ht_entry *entry;
|
||||
struct ht_item *item, *tmp;
|
||||
size_t slot = hash % h->ht_nentries;
|
||||
|
||||
entry = &h->ht_entries[slot];
|
||||
|
||||
TAILQ_FOREACH_SAFE(item, &entry->hte_items, hti_link, tmp) {
|
||||
if (item->hti_hash == hash) {
|
||||
TAILQ_REMOVE(&entry->hte_items, item, hti_link);
|
||||
free(item->hti_data);
|
||||
free(item);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
errno = ENOENT;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int
|
||||
ht_remove_at_iter(struct ht_iter *iter)
|
||||
{
|
||||
assert(iter != NULL);
|
||||
|
||||
if (iter->htit_cursor == NULL) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
TAILQ_REMOVE(&iter->htit_parent->ht_entries[iter->htit_slot].hte_items,
|
||||
iter->htit_cursor, hti_link);
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
ht_iter(struct ht *h, struct ht_iter *iter)
|
||||
{
|
||||
iter->htit_parent = h;
|
||||
iter->htit_slot = 0;
|
||||
iter->htit_cursor = TAILQ_FIRST(&h->ht_entries[0].hte_items);
|
||||
}
|
||||
|
||||
void *
|
||||
ht_next(struct ht_iter *iter)
|
||||
{
|
||||
struct ht_item *item;
|
||||
|
||||
item = iter->htit_cursor;
|
||||
|
||||
retry:
|
||||
if ((iter->htit_cursor = TAILQ_NEXT(iter->htit_cursor, hti_link)) == NULL)
|
||||
{
|
||||
if (iter->htit_slot == iter->htit_parent->ht_nentries)
|
||||
return (NULL);
|
||||
|
||||
iter->htit_slot++;
|
||||
goto retry;
|
||||
|
||||
}
|
||||
|
||||
return (item);
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
* 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_HASHTABLE_H
|
||||
#define LIB9P_HASHTABLE_H
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
struct ht {
|
||||
struct ht_entry * ht_entries;
|
||||
size_t ht_nentries;
|
||||
};
|
||||
|
||||
struct ht_entry {
|
||||
TAILQ_HEAD(, ht_item) hte_items;
|
||||
};
|
||||
|
||||
struct ht_item {
|
||||
uint32_t hti_hash;
|
||||
void * hti_data;
|
||||
TAILQ_ENTRY(ht_item) hti_link;
|
||||
};
|
||||
|
||||
struct ht_iter {
|
||||
struct ht * htit_parent;
|
||||
struct ht_item * htit_cursor;
|
||||
size_t htit_slot;
|
||||
};
|
||||
|
||||
void ht_init(struct ht *h, size_t size);
|
||||
void ht_destroy(struct ht *h);
|
||||
void *ht_find(struct ht *h, uint32_t hash);
|
||||
int ht_add(struct ht *h, uint32_t hash, void *value);
|
||||
int ht_remove(struct ht *h, uint32_t hash);
|
||||
int ht_remove_at_iter(struct ht_iter *iter);
|
||||
void ht_iter(struct ht *h, struct ht_iter *iter);
|
||||
void *ht_next(struct ht_iter *iter);
|
||||
|
||||
#endif /* LIB9P_HASHTABLE_H */
|
186
lib9p/lib9p.h
186
lib9p/lib9p.h
|
@ -1,186 +0,0 @@
|
|||
/*
|
||||
* 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_LIB9P_H
|
||||
#define LIB9P_LIB9P_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/uio.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sbuf.h>
|
||||
#else
|
||||
#include "sbuf/sbuf.h"
|
||||
#endif
|
||||
|
||||
#include "fcall.h"
|
||||
#include "hashtable.h"
|
||||
|
||||
#define L9P_DEFAULT_MSIZE 8192
|
||||
#define L9P_MAX_IOV 8
|
||||
|
||||
struct l9p_request;
|
||||
|
||||
typedef int (l9p_get_response_buffer_t) (struct l9p_request *,
|
||||
struct iovec *, size_t *, void *);
|
||||
|
||||
typedef int (l9p_send_response_t) (struct l9p_request *, const struct iovec *,
|
||||
const size_t, const size_t, void *);
|
||||
|
||||
enum l9p_pack_mode {
|
||||
L9P_PACK,
|
||||
L9P_UNPACK
|
||||
};
|
||||
|
||||
enum l9p_integer_type {
|
||||
L9P_BYTE = 1,
|
||||
L9P_WORD = 2,
|
||||
L9P_DWORD = 4,
|
||||
L9P_QWORD = 8
|
||||
};
|
||||
|
||||
enum l9p_version {
|
||||
L9P_2000 = 0,
|
||||
L9P_2000U = 1,
|
||||
L9P_2000L = 2,
|
||||
L9P_INVALID_VERSION = 3
|
||||
};
|
||||
|
||||
struct l9p_message {
|
||||
enum l9p_pack_mode lm_mode;
|
||||
struct iovec lm_iov[L9P_MAX_IOV];
|
||||
size_t lm_niov;
|
||||
size_t lm_cursor_iov;
|
||||
size_t lm_cursor_offset;
|
||||
size_t lm_size;
|
||||
};
|
||||
|
||||
struct l9p_request {
|
||||
uint32_t lr_tag;
|
||||
struct l9p_message lr_req_msg;
|
||||
struct l9p_message lr_resp_msg;
|
||||
struct l9p_message lr_readdir_msg;
|
||||
union l9p_fcall lr_req;
|
||||
union l9p_fcall lr_resp;
|
||||
struct l9p_openfile *lr_fid;
|
||||
struct l9p_openfile *lr_newfid;
|
||||
struct l9p_connection *lr_conn;
|
||||
pthread_t lr_thread;
|
||||
void *lr_aux;
|
||||
struct iovec lr_data_iov[L9P_MAX_IOV];
|
||||
size_t lr_data_niov;
|
||||
};
|
||||
|
||||
struct l9p_openfile {
|
||||
void *lo_aux;
|
||||
uint32_t lo_fid;
|
||||
struct l9p_qid lo_qid;
|
||||
struct l9p_connection *lo_conn;
|
||||
};
|
||||
|
||||
struct l9p_connection {
|
||||
struct l9p_server *lc_server;
|
||||
enum l9p_version lc_version;
|
||||
pthread_mutex_t lc_send_lock;
|
||||
uint32_t lc_msize;
|
||||
uint32_t lc_max_io_size;
|
||||
l9p_send_response_t *lc_send_response;
|
||||
l9p_get_response_buffer_t *lc_get_response_buffer;
|
||||
void *lc_get_response_buffer_aux;
|
||||
void *lc_send_response_aux;
|
||||
void *lc_softc;
|
||||
struct ht lc_files;
|
||||
struct ht lc_requests;
|
||||
LIST_ENTRY(l9p_connection) lc_link;
|
||||
};
|
||||
|
||||
struct l9p_server {
|
||||
struct l9p_backend *ls_backend;
|
||||
enum l9p_version ls_max_version;
|
||||
LIST_HEAD(, l9p_connection) ls_conns;
|
||||
};
|
||||
|
||||
struct l9p_backend {
|
||||
void *softc;
|
||||
void (*attach)(void *, struct l9p_request *);
|
||||
void (*clunk)(void *, struct l9p_request *);
|
||||
void (*create)(void *, struct l9p_request *);
|
||||
void (*flush)(void *, struct l9p_request *);
|
||||
void (*open)(void *, struct l9p_request *);
|
||||
void (*read)(void *, struct l9p_request *);
|
||||
void (*remove)(void *, struct l9p_request *);
|
||||
void (*stat)(void *, struct l9p_request *);
|
||||
void (*walk)(void *, struct l9p_request *);
|
||||
void (*write)(void *, struct l9p_request *);
|
||||
void (*wstat)(void *, struct l9p_request *);
|
||||
void (*freefid)(void *, struct l9p_openfile *);
|
||||
};
|
||||
|
||||
int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
|
||||
enum l9p_version version);
|
||||
int l9p_pustat(struct l9p_message *msg, struct l9p_stat *s,
|
||||
enum l9p_version version);
|
||||
uint16_t l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version);
|
||||
int l9p_pack_stat(struct l9p_request *req, struct l9p_stat *s);
|
||||
|
||||
int l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend);
|
||||
|
||||
int l9p_connection_init(struct l9p_server *server,
|
||||
struct l9p_connection **connp);
|
||||
void l9p_connection_free(struct l9p_connection *conn);
|
||||
void l9p_connection_on_send_response(struct l9p_connection *conn,
|
||||
l9p_send_response_t *cb, void *aux);
|
||||
void l9p_connection_on_get_response_buffer(struct l9p_connection *conn,
|
||||
l9p_get_response_buffer_t *cb, void *aux);
|
||||
void l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov,
|
||||
size_t niov, void *aux);
|
||||
void l9p_connection_close(struct l9p_connection *conn);
|
||||
struct l9p_openfile *l9p_connection_alloc_fid(struct l9p_connection *conn,
|
||||
uint32_t fid);
|
||||
void l9p_connection_remove_fid(struct l9p_connection *conn,
|
||||
struct l9p_openfile *fid);
|
||||
|
||||
void l9p_dispatch_request(struct l9p_request *req);
|
||||
void l9p_respond(struct l9p_request *req, int errnum);
|
||||
|
||||
void l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2,
|
||||
size_t *niov2, size_t seek);
|
||||
size_t l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length);
|
||||
void l9p_describe_qid(struct l9p_qid *qid, struct sbuf *sb);
|
||||
void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version,
|
||||
struct sbuf *sb);
|
||||
void l9p_describe_stat(struct l9p_stat *st, struct sbuf *sb);
|
||||
void l9p_freefcall(union l9p_fcall *fcall);
|
||||
void l9p_freestat(struct l9p_stat *stat);
|
||||
|
||||
int l9p_backend_fs_init(struct l9p_backend **backendp, const char *root);
|
||||
|
||||
#endif /* LIB9P_LIB9P_H */
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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_LIB9P_IMPL_H
|
||||
#define LIB9P_LIB9P_IMPL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef _KERNEL
|
||||
static inline void *
|
||||
l9p_malloc(size_t size)
|
||||
{
|
||||
void *r = malloc(size);
|
||||
|
||||
if (r == NULL) {
|
||||
fprintf(stderr, "cannot allocate %zd bytes: out of memory\n",
|
||||
size);
|
||||
abort();
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
l9p_calloc(size_t n, size_t size)
|
||||
{
|
||||
void *r = calloc(n, size);
|
||||
|
||||
if (r == NULL) {
|
||||
fprintf(stderr, "cannot allocate %zd bytes: out of memory\n",
|
||||
n * size);
|
||||
abort();
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static inline void *
|
||||
l9p_realloc(void *ptr, size_t newsize)
|
||||
{
|
||||
void *r = realloc(ptr, newsize);
|
||||
|
||||
if (r == NULL) {
|
||||
fprintf(stderr, "cannot allocate %zd bytes: out of memory\n",
|
||||
newsize);
|
||||
abort();
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* LIB9P_LIB9P_IMPL_H */
|
49
lib9p/log.c
49
lib9p/log.c
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "log.h"
|
||||
|
||||
static const char *l9p_log_level_names[] = {
|
||||
"DEBUG",
|
||||
"INFO",
|
||||
"WARN",
|
||||
"ERROR"
|
||||
};
|
||||
|
||||
void
|
||||
l9p_logf(enum l9p_log_level level, const char *func, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
fprintf(stderr, "[%s]\t %s: ", l9p_log_level_names[level], func);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
}
|
47
lib9p/log.h
47
lib9p/log.h
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* 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_LOG_H
|
||||
#define LIB9P_LOG_H
|
||||
|
||||
enum l9p_log_level
|
||||
{
|
||||
L9P_DEBUG,
|
||||
L9P_INFO,
|
||||
L9P_WARNING,
|
||||
L9P_ERROR
|
||||
};
|
||||
|
||||
void l9p_logf(enum l9p_log_level level, const char *func, const char *fmt, ...);
|
||||
|
||||
#if defined(L9P_DEBUG)
|
||||
#define L9P_LOG(level, fmt, ...) l9p_logf(level, __func__, fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
#define L9P_LOG(level, fmt, ...)
|
||||
#endif
|
||||
|
||||
#endif /* LIB9P_LOG_H */
|
453
lib9p/pack.c
453
lib9p/pack.c
|
@ -1,453 +0,0 @@
|
|||
/*
|
||||
* 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 <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
|
||||
#define N(ary) (sizeof(ary) / sizeof(*ary))
|
||||
#define STRING_SIZE(s) (L9P_WORD + (s != NULL ? (uint16_t)strlen(s) : 0))
|
||||
#define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD)
|
||||
|
||||
static int l9p_iov_io(struct l9p_message *, void *, size_t);
|
||||
static inline int l9p_pu8(struct l9p_message *, uint8_t *);
|
||||
static inline int l9p_pu16(struct l9p_message *, uint16_t *);
|
||||
static inline int l9p_pu32(struct l9p_message *, uint32_t *);
|
||||
static inline int l9p_pu64(struct l9p_message *, uint64_t *);
|
||||
static int l9p_pustring(struct l9p_message *, char **s);
|
||||
static int l9p_pustrings(struct l9p_message *, uint16_t *, char *[], size_t);
|
||||
static int l9p_puqid(struct l9p_message *, struct l9p_qid *);
|
||||
static int l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q);
|
||||
|
||||
static int
|
||||
l9p_iov_io(struct l9p_message *msg, void *buffer, size_t len)
|
||||
{
|
||||
size_t done = 0;
|
||||
size_t left = len;
|
||||
|
||||
assert(msg != NULL);
|
||||
|
||||
if (len == 0)
|
||||
return (0);
|
||||
|
||||
if (msg->lm_cursor_iov >= msg->lm_niov)
|
||||
return (-1);
|
||||
|
||||
assert(buffer != NULL);
|
||||
|
||||
while (left > 0) {
|
||||
size_t idx = msg->lm_cursor_iov;
|
||||
size_t space = msg->lm_iov[idx].iov_len - msg->lm_cursor_offset;
|
||||
size_t towrite = MIN(space, left);
|
||||
|
||||
if (msg->lm_mode == L9P_PACK) {
|
||||
memcpy((char *)msg->lm_iov[idx].iov_base +
|
||||
msg->lm_cursor_offset, (char *)buffer + done,
|
||||
towrite);
|
||||
}
|
||||
|
||||
if (msg->lm_mode == L9P_UNPACK) {
|
||||
memcpy((char *)buffer + done,
|
||||
(char *)msg->lm_iov[idx].iov_base +
|
||||
msg->lm_cursor_offset, towrite);
|
||||
}
|
||||
|
||||
msg->lm_cursor_offset += towrite;
|
||||
|
||||
if (space - towrite == 0) {
|
||||
/* Advance to next iov */
|
||||
msg->lm_cursor_iov++;
|
||||
msg->lm_cursor_offset = 0;
|
||||
|
||||
if (msg->lm_cursor_iov > msg->lm_niov)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
done += towrite;
|
||||
left -= towrite;
|
||||
}
|
||||
|
||||
msg->lm_size += done;
|
||||
return ((int)done);
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu8(struct l9p_message *msg, uint8_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof (uint8_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu16(struct l9p_message *msg, uint16_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof (uint16_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu32(struct l9p_message *msg, uint32_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof (uint32_t)));
|
||||
}
|
||||
|
||||
static inline int
|
||||
l9p_pu64(struct l9p_message *msg, uint64_t *val)
|
||||
{
|
||||
|
||||
return (l9p_iov_io(msg, val, sizeof (uint64_t)));
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_pustring(struct l9p_message *msg, char **s)
|
||||
{
|
||||
uint16_t len;
|
||||
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
len = *s != NULL ? (uint16_t)strlen(*s) : 0;
|
||||
|
||||
if (l9p_pu16(msg, &len) < 0)
|
||||
return (-1);
|
||||
|
||||
if (msg->lm_mode == L9P_UNPACK)
|
||||
*s = l9p_calloc(1, len + 1);
|
||||
|
||||
if (l9p_iov_io(msg, *s, len) < 0)
|
||||
return (-1);
|
||||
|
||||
return (len + 2);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[],
|
||||
size_t max)
|
||||
{
|
||||
size_t i;
|
||||
int ret;
|
||||
int r = 0;
|
||||
|
||||
l9p_pu16(msg, num);
|
||||
|
||||
for (i = 0; i < MIN(*num, max); i++) {
|
||||
ret = l9p_pustring(msg, &strings[i]);
|
||||
if (ret < 1)
|
||||
return (-1);
|
||||
|
||||
r += ret;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
r += l9p_pu8(msg, (uint8_t *) & qid->type);
|
||||
r += l9p_pu32(msg, &qid->version);
|
||||
r += l9p_pu64(msg, &qid->path);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids)
|
||||
{
|
||||
int i, ret, r = 0;
|
||||
l9p_pu16(msg, num);
|
||||
|
||||
for (i = 0; i < *num; i++) {
|
||||
ret = l9p_puqid(msg, &qids[i]);
|
||||
if (ret < 0)
|
||||
return (-1);
|
||||
|
||||
r += ret;
|
||||
}
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat,
|
||||
enum l9p_version version)
|
||||
{
|
||||
int r = 0;
|
||||
uint16_t size;
|
||||
|
||||
if (msg->lm_mode == L9P_PACK)
|
||||
size = l9p_sizeof_stat(stat, version) - 2;
|
||||
|
||||
r += l9p_pu16(msg, &size);
|
||||
r += l9p_pu16(msg, &stat->type);
|
||||
r += l9p_pu32(msg, &stat->dev);
|
||||
r += l9p_puqid(msg, &stat->qid);
|
||||
r += l9p_pu32(msg, &stat->mode);
|
||||
r += l9p_pu32(msg, &stat->atime);
|
||||
r += l9p_pu32(msg, &stat->mtime);
|
||||
r += l9p_pu64(msg, &stat->length);
|
||||
r += l9p_pustring(msg, &stat->name);
|
||||
r += l9p_pustring(msg, &stat->uid);
|
||||
r += l9p_pustring(msg, &stat->gid);
|
||||
r += l9p_pustring(msg, &stat->muid);
|
||||
|
||||
if (version == L9P_2000U) {
|
||||
r += l9p_pustring(msg, &stat->extension);
|
||||
r += l9p_pu32(msg, &stat->n_uid);
|
||||
r += l9p_pu32(msg, &stat->n_gid);
|
||||
r += l9p_pu32(msg, &stat->n_muid);
|
||||
}
|
||||
|
||||
if (r < size + 2)
|
||||
return (-1);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall,
|
||||
enum l9p_version version)
|
||||
{
|
||||
uint32_t length = 0;
|
||||
|
||||
l9p_pu32(msg, &length);
|
||||
l9p_pu8(msg, &fcall->hdr.type);
|
||||
l9p_pu16(msg, &fcall->hdr.tag);
|
||||
|
||||
switch (fcall->hdr.type) {
|
||||
case L9P_TVERSION:
|
||||
case L9P_RVERSION:
|
||||
l9p_pu32(msg, &fcall->version.msize);
|
||||
l9p_pustring(msg, &fcall->version.version);
|
||||
break;
|
||||
|
||||
case L9P_TAUTH:
|
||||
l9p_pu32(msg, &fcall->tauth.afid);
|
||||
l9p_pustring(msg, &fcall->tauth.uname);
|
||||
l9p_pustring(msg, &fcall->tauth.aname);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->tauth.n_uname);
|
||||
break;
|
||||
|
||||
case L9P_RAUTH:
|
||||
l9p_puqid(msg, &fcall->rauth.aqid);
|
||||
break;
|
||||
|
||||
case L9P_RATTACH:
|
||||
l9p_puqid(msg, &fcall->rattach.qid);
|
||||
break;
|
||||
|
||||
case L9P_TATTACH:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->tattach.afid);
|
||||
l9p_pustring(msg, &fcall->tattach.uname);
|
||||
l9p_pustring(msg, &fcall->tattach.aname);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->tattach.n_uname);
|
||||
break;
|
||||
|
||||
case L9P_RERROR:
|
||||
l9p_pustring(msg, &fcall->error.ename);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pu32(msg, &fcall->error.errnum);
|
||||
break;
|
||||
|
||||
case L9P_TFLUSH:
|
||||
l9p_pu16(msg, &fcall->tflush.oldtag);
|
||||
break;
|
||||
|
||||
case L9P_TWALK:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu32(msg, &fcall->twalk.newfid);
|
||||
l9p_pustrings(msg, &fcall->twalk.nwname,
|
||||
fcall->twalk.wname, N(fcall->twalk.wname));
|
||||
break;
|
||||
|
||||
case L9P_RWALK:
|
||||
l9p_puqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
|
||||
break;
|
||||
|
||||
case L9P_TOPEN:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu8(msg, &fcall->topen.mode);
|
||||
break;
|
||||
|
||||
case L9P_ROPEN:
|
||||
case L9P_RCREATE:
|
||||
l9p_puqid(msg, &fcall->ropen.qid);
|
||||
l9p_pu32(msg, &fcall->ropen.iounit);
|
||||
break;
|
||||
|
||||
case L9P_TCREATE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pustring(msg, &fcall->tcreate.name);
|
||||
l9p_pu32(msg, &fcall->tcreate.perm);
|
||||
l9p_pu8(msg, &fcall->tcreate.mode);
|
||||
if (version == L9P_2000U)
|
||||
l9p_pustring(msg, &fcall->tcreate.extension);
|
||||
break;
|
||||
|
||||
case L9P_TREAD:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_RREAD:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_TWRITE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu64(msg, &fcall->io.offset);
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_RWRITE:
|
||||
l9p_pu32(msg, &fcall->io.count);
|
||||
break;
|
||||
|
||||
case L9P_TCLUNK:
|
||||
case L9P_TSTAT:
|
||||
case L9P_TREMOVE:
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
break;
|
||||
|
||||
case L9P_RSTAT:
|
||||
{
|
||||
uint16_t size = l9p_sizeof_stat(&fcall->rstat.stat,
|
||||
version);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->rstat.stat, version);
|
||||
}
|
||||
break;
|
||||
|
||||
case L9P_TWSTAT:
|
||||
{
|
||||
uint16_t size;
|
||||
l9p_pu32(msg, &fcall->hdr.fid);
|
||||
l9p_pu16(msg, &size);
|
||||
l9p_pustat(msg, &fcall->twstat.stat, version);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg->lm_mode == L9P_PACK) {
|
||||
/* Rewind to the beginning */
|
||||
uint32_t len = (uint32_t)msg->lm_size;
|
||||
msg->lm_cursor_offset = 0;
|
||||
msg->lm_cursor_iov = 0;
|
||||
|
||||
/*
|
||||
* Subtract 4 bytes from message size, becase we're
|
||||
* overwriting size (rewinding message to the beginning)
|
||||
* and writing again.
|
||||
*/
|
||||
msg->lm_size -= sizeof (uint32_t);
|
||||
|
||||
if (fcall->hdr.type == L9P_RREAD)
|
||||
len += fcall->io.count;
|
||||
|
||||
l9p_pu32(msg, &len);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_freefcall(union l9p_fcall *fcall)
|
||||
{
|
||||
uint16_t i;
|
||||
|
||||
switch (fcall->hdr.type) {
|
||||
case L9P_TVERSION:
|
||||
case L9P_RVERSION:
|
||||
free(fcall->version.version);
|
||||
return;
|
||||
case L9P_TATTACH:
|
||||
free(fcall->tattach.aname);
|
||||
free(fcall->tattach.uname);
|
||||
return;
|
||||
case L9P_TWALK:
|
||||
for (i = 0; i < fcall->twalk.nwname; i++)
|
||||
free(fcall->twalk.wname[i]);
|
||||
return;
|
||||
case L9P_TCREATE:
|
||||
case L9P_TOPEN:
|
||||
free(fcall->tcreate.name);
|
||||
free(fcall->tcreate.extension);
|
||||
return;
|
||||
case L9P_RSTAT:
|
||||
l9p_freestat(&fcall->rstat.stat);
|
||||
return;
|
||||
case L9P_TWSTAT:
|
||||
l9p_freestat(&fcall->twstat.stat);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
l9p_freestat(struct l9p_stat *stat)
|
||||
{
|
||||
free(stat->name);
|
||||
free(stat->extension);
|
||||
free(stat->uid);
|
||||
free(stat->gid);
|
||||
free(stat->muid);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
l9p_sizeof_stat(struct l9p_stat *stat, enum l9p_version version)
|
||||
{
|
||||
uint16_t size = L9P_WORD /* size */
|
||||
+ L9P_WORD /* type */
|
||||
+ L9P_DWORD /* dev */
|
||||
+ QID_SIZE /* qid */
|
||||
+ 3 * L9P_DWORD /* mode, atime, mtime */
|
||||
+ L9P_QWORD /* length */
|
||||
+ STRING_SIZE(stat->name)
|
||||
+ STRING_SIZE(stat->uid)
|
||||
+ STRING_SIZE(stat->gid)
|
||||
+ STRING_SIZE(stat->muid);
|
||||
|
||||
if (version == L9P_2000U) {
|
||||
size += STRING_SIZE(stat->extension)
|
||||
+ 3 * L9P_DWORD;
|
||||
}
|
||||
|
||||
return (size);
|
||||
}
|
444
lib9p/request.c
444
lib9p/request.c
|
@ -1,444 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sbuf.h>
|
||||
#else
|
||||
#include "sbuf/sbuf.h"
|
||||
#endif
|
||||
#include "lib9p.h"
|
||||
#include "lib9p_impl.h"
|
||||
#include "fcall.h"
|
||||
#include "hashtable.h"
|
||||
#include "log.h"
|
||||
|
||||
#define N(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
static void l9p_dispatch_tversion(struct l9p_request *req);
|
||||
static void l9p_dispatch_tattach(struct l9p_request *req);
|
||||
static void l9p_dispatch_tclunk(struct l9p_request *req);
|
||||
static void l9p_dispatch_tflush(struct l9p_request *req);
|
||||
static void l9p_dispatch_tcreate(struct l9p_request *req);
|
||||
static void l9p_dispatch_topen(struct l9p_request *req);
|
||||
static void l9p_dispatch_tread(struct l9p_request *req);
|
||||
static void l9p_dispatch_tremove(struct l9p_request *req);
|
||||
static void l9p_dispatch_tstat(struct l9p_request *req);
|
||||
static void l9p_dispatch_twalk(struct l9p_request *req);
|
||||
static void l9p_dispatch_twrite(struct l9p_request *req);
|
||||
static void l9p_dispatch_twstat(struct l9p_request *req);
|
||||
|
||||
static const struct
|
||||
{
|
||||
enum l9p_ftype type;
|
||||
void (*handler)(struct l9p_request *);
|
||||
} l9p_handlers[] = {
|
||||
{L9P_TVERSION, l9p_dispatch_tversion},
|
||||
{L9P_TATTACH, l9p_dispatch_tattach},
|
||||
{L9P_TCLUNK, l9p_dispatch_tclunk},
|
||||
{L9P_TFLUSH, l9p_dispatch_tflush},
|
||||
{L9P_TCREATE, l9p_dispatch_tcreate},
|
||||
{L9P_TOPEN, l9p_dispatch_topen},
|
||||
{L9P_TREAD, l9p_dispatch_tread},
|
||||
{L9P_TWRITE, l9p_dispatch_twrite},
|
||||
{L9P_TREMOVE, l9p_dispatch_tremove},
|
||||
{L9P_TSTAT, l9p_dispatch_tstat},
|
||||
{L9P_TWALK, l9p_dispatch_twalk},
|
||||
{L9P_TWSTAT, l9p_dispatch_twstat}
|
||||
};
|
||||
|
||||
static const char *l9p_versions[] = {
|
||||
"9P2000",
|
||||
"9P2000.u",
|
||||
"9P2000.L"
|
||||
};
|
||||
|
||||
void
|
||||
l9p_dispatch_request(struct l9p_request *req)
|
||||
{
|
||||
#if defined(L9P_DEBUG)
|
||||
struct sbuf *sb;
|
||||
#endif
|
||||
size_t i;
|
||||
|
||||
#if defined(L9P_DEBUG)
|
||||
sb = sbuf_new_auto();
|
||||
l9p_describe_fcall(&req->lr_req, req->lr_conn->lc_version, sb);
|
||||
sbuf_done(sb);
|
||||
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
#endif
|
||||
|
||||
req->lr_tag = req->lr_req.hdr.tag;
|
||||
|
||||
for (i = 0; i < N(l9p_handlers); i++) {
|
||||
if (req->lr_req.hdr.type == l9p_handlers[i].type) {
|
||||
l9p_handlers[i].handler(req);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
L9P_LOG(L9P_WARNING, "unknown request of type %d", req->lr_req.hdr.type);
|
||||
l9p_respond(req, ENOSYS);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_respond(struct l9p_request *req, int errnum)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
size_t iosize;
|
||||
#if defined(L9P_DEBUG)
|
||||
struct sbuf *sb;
|
||||
#endif
|
||||
|
||||
switch (req->lr_req.hdr.type) {
|
||||
case L9P_TATTACH:
|
||||
if (errnum != 0)
|
||||
l9p_connection_remove_fid(conn, req->lr_fid);
|
||||
|
||||
break;
|
||||
case L9P_TCLUNK:
|
||||
case L9P_TREMOVE:
|
||||
if (req->lr_fid != NULL)
|
||||
l9p_connection_remove_fid(conn, req->lr_fid);
|
||||
break;
|
||||
|
||||
case L9P_TWALK:
|
||||
if (errnum != 0 && req->lr_newfid != NULL &&
|
||||
req->lr_newfid != req->lr_fid)
|
||||
l9p_connection_remove_fid(conn, req->lr_newfid);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
req->lr_resp.hdr.tag = req->lr_req.hdr.tag;
|
||||
|
||||
if (errnum == 0)
|
||||
req->lr_resp.hdr.type = req->lr_req.hdr.type + 1;
|
||||
else {
|
||||
req->lr_resp.hdr.type = L9P_RERROR;
|
||||
req->lr_resp.error.ename = strerror(errnum);
|
||||
req->lr_resp.error.errnum = (uint32_t)errnum;
|
||||
}
|
||||
|
||||
#if defined(L9P_DEBUG)
|
||||
sb = sbuf_new_auto();
|
||||
l9p_describe_fcall(&req->lr_resp, L9P_2000, sb);
|
||||
sbuf_done(sb);
|
||||
|
||||
L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb));
|
||||
sbuf_delete(sb);
|
||||
#endif
|
||||
|
||||
if (l9p_pufcall(&req->lr_resp_msg, &req->lr_resp, conn->lc_version) != 0) {
|
||||
L9P_LOG(L9P_ERROR, "cannot pack response");
|
||||
goto out;
|
||||
}
|
||||
|
||||
iosize = req->lr_resp_msg.lm_size;
|
||||
|
||||
/* Include I/O size in calculation for Rread response */
|
||||
if (req->lr_resp.hdr.type == L9P_RREAD)
|
||||
iosize += req->lr_resp.io.count;
|
||||
|
||||
conn->lc_send_response(req, req->lr_resp_msg.lm_iov,
|
||||
req->lr_resp_msg.lm_niov, iosize, conn->lc_send_response_aux);
|
||||
|
||||
out:
|
||||
l9p_freefcall(&req->lr_req);
|
||||
l9p_freefcall(&req->lr_resp);
|
||||
free(req);
|
||||
}
|
||||
|
||||
int
|
||||
l9p_pack_stat(struct l9p_request *req, struct l9p_stat *st)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
struct l9p_message *msg = &req->lr_readdir_msg;
|
||||
uint16_t size = l9p_sizeof_stat(st, conn->lc_version);
|
||||
|
||||
if (msg->lm_size == 0) {
|
||||
/* Initialize message */
|
||||
msg->lm_mode = L9P_PACK;
|
||||
msg->lm_niov = req->lr_data_niov;
|
||||
memcpy(msg->lm_iov, req->lr_data_iov,
|
||||
sizeof (struct iovec) * req->lr_data_niov);
|
||||
}
|
||||
|
||||
if (req->lr_resp.io.count + size > req->lr_req.io.count) {
|
||||
l9p_freestat(st);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (l9p_pustat(msg, st, conn->lc_version) < 0) {
|
||||
l9p_freestat(st);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
req->lr_resp.io.count += size;
|
||||
l9p_freestat(st);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tversion(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
enum l9p_version remote_version = L9P_INVALID_VERSION;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < N(l9p_versions); i++) {
|
||||
if (strcmp(req->lr_req.version.version, l9p_versions[i]) == 0) {
|
||||
remote_version = (enum l9p_version)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (remote_version == L9P_INVALID_VERSION) {
|
||||
L9P_LOG(L9P_ERROR, "unsupported remote version: %s",
|
||||
req->lr_req.version.version);
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
L9P_LOG(L9P_INFO, "remote version: %s", l9p_versions[remote_version]);
|
||||
L9P_LOG(L9P_INFO, "local version: %s",
|
||||
l9p_versions[conn->lc_server->ls_max_version]);
|
||||
|
||||
conn->lc_version = MIN(remote_version, conn->lc_server->ls_max_version);
|
||||
conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize);
|
||||
conn->lc_max_io_size = conn->lc_msize - 24;
|
||||
req->lr_resp.version.version = strdup(l9p_versions[conn->lc_version]);
|
||||
req->lr_resp.version.msize = conn->lc_msize;
|
||||
l9p_respond(req, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tattach(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL)
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
|
||||
conn->lc_server->ls_backend->attach(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tclunk(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->clunk(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tflush(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
if (!conn->lc_server->ls_backend->flush) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->flush(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tcreate(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->create) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->create(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_topen(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->open) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->open(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tread(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov,
|
||||
req->lr_data_iov, &req->lr_data_niov, 11);
|
||||
|
||||
conn->lc_server->ls_backend->read(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tremove(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->remove) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->remove(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_tstat(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->stat) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->stat(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twalk(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) {
|
||||
req->lr_newfid = l9p_connection_alloc_fid(conn,
|
||||
req->lr_req.twalk.newfid);
|
||||
if (req->lr_newfid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->walk) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->walk(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twrite(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.twalk.hdr.fid);
|
||||
if (req->lr_fid == NULL) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->write) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
l9p_seek_iov(req->lr_req_msg.lm_iov, req->lr_req_msg.lm_niov,
|
||||
req->lr_data_iov, &req->lr_data_niov, 23);
|
||||
|
||||
conn->lc_server->ls_backend->write(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
||||
|
||||
static void
|
||||
l9p_dispatch_twstat(struct l9p_request *req)
|
||||
{
|
||||
struct l9p_connection *conn = req->lr_conn;
|
||||
|
||||
req->lr_fid = ht_find(&conn->lc_files, req->lr_req.hdr.fid);
|
||||
if (!req->lr_fid) {
|
||||
l9p_respond(req, EBADF);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn->lc_server->ls_backend->wstat) {
|
||||
l9p_respond(req, ENOSYS);
|
||||
return;
|
||||
}
|
||||
|
||||
conn->lc_server->ls_backend->wstat(conn->lc_server->ls_backend->softc, req);
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimal libsbuf reimplementation for Mac OS X.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "sbuf.h"
|
||||
|
||||
#define SBUF_INITIAL_SIZE 128
|
||||
|
||||
struct sbuf *
|
||||
sbuf_new_auto()
|
||||
{
|
||||
struct sbuf *s;
|
||||
|
||||
s = malloc(sizeof(struct sbuf));
|
||||
s->s_buf = calloc(1, SBUF_INITIAL_SIZE + 1);
|
||||
s->s_capacity = SBUF_INITIAL_SIZE;
|
||||
s->s_size = 0;
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
int
|
||||
sbuf_printf(struct sbuf *s, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = sbuf_vprintf(s, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
sbuf_vprintf(struct sbuf *s, const char *fmt, va_list args)
|
||||
{
|
||||
va_list copy;
|
||||
int req;
|
||||
|
||||
va_copy(copy, args);
|
||||
req = vsnprintf(NULL, 0, fmt, copy);
|
||||
va_end(copy);
|
||||
|
||||
if (s->s_size + req >= s->s_capacity) {
|
||||
s->s_capacity = s->s_size + req + 1;
|
||||
s->s_buf = realloc(s->s_buf, (size_t)s->s_capacity);
|
||||
}
|
||||
|
||||
req = vsnprintf(s->s_buf + s->s_size, req + 1, fmt, args);
|
||||
s->s_size += req;
|
||||
|
||||
return (req);
|
||||
}
|
||||
|
||||
char *
|
||||
sbuf_data(struct sbuf *s)
|
||||
{
|
||||
return (s->s_buf);
|
||||
}
|
||||
|
||||
int
|
||||
sbuf_done(struct sbuf *s)
|
||||
{
|
||||
s->s_buf[s->s_size] = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
sbuf_delete(struct sbuf *s)
|
||||
{
|
||||
free(s->s_buf);
|
||||
free(s);
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Minimal libsbuf reimplementation for Mac OS X.
|
||||
*/
|
||||
|
||||
#ifndef LIB9P_SBUF_H
|
||||
#define LIB9P_SBUF_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
struct sbuf
|
||||
{
|
||||
char *s_buf;
|
||||
int s_size;
|
||||
int s_capacity;
|
||||
int s_position;
|
||||
};
|
||||
|
||||
struct sbuf *sbuf_new_auto(void);
|
||||
int sbuf_printf(struct sbuf *s, const char *fmt, ...);
|
||||
int sbuf_vprintf(struct sbuf *s, const char *fmt, va_list args);
|
||||
int sbuf_done(struct sbuf *s);
|
||||
void sbuf_delete(struct sbuf *s);
|
||||
char *sbuf_data(struct sbuf *s);
|
||||
|
||||
#endif /* LIB9P_SBUF_H */
|
||||
|
|
@ -1,308 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netdb.h>
|
||||
#include "../lib9p.h"
|
||||
#include "../lib9p_impl.h"
|
||||
#include "../log.h"
|
||||
#include "socket.h"
|
||||
|
||||
struct l9p_socket_softc
|
||||
{
|
||||
struct l9p_connection *ls_conn;
|
||||
struct sockaddr ls_sockaddr;
|
||||
socklen_t ls_socklen;
|
||||
pthread_t ls_thread;
|
||||
int ls_fd;
|
||||
};
|
||||
|
||||
static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *);
|
||||
static int l9p_socket_get_response_buffer(struct l9p_request *,
|
||||
struct iovec *, size_t *, void *);
|
||||
static int l9p_socket_send_response(struct l9p_request *, const struct iovec *,
|
||||
const size_t, const size_t, void *);
|
||||
static void *l9p_socket_thread(void *);
|
||||
static ssize_t xread(int, void *, size_t);
|
||||
static ssize_t xwrite(int, void *, size_t);
|
||||
|
||||
int
|
||||
l9p_start_server(struct l9p_server *server, const char *host, const char *port)
|
||||
{
|
||||
struct addrinfo *res, *res0, hints;
|
||||
struct kevent kev[2];
|
||||
struct kevent event[2];
|
||||
int err, kq, i, val, evs, nsockets = 0;
|
||||
int sockets[2];
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
err = getaddrinfo(host, port, &hints, &res0);
|
||||
|
||||
if (err)
|
||||
return (-1);
|
||||
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
int s = socket(res->ai_family, res->ai_socktype,
|
||||
res->ai_protocol);
|
||||
|
||||
val = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
|
||||
|
||||
if (s < 0)
|
||||
continue;
|
||||
|
||||
if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
|
||||
close(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
sockets[nsockets] = s;
|
||||
EV_SET(&kev[nsockets++], s, EVFILT_READ, EV_ADD | EV_ENABLE, 0,
|
||||
0, 0);
|
||||
listen(s, 10);
|
||||
}
|
||||
|
||||
kq = kqueue();
|
||||
|
||||
if (kevent(kq, kev, nsockets, NULL, 0, NULL) < 0) {
|
||||
L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
evs = kevent(kq, NULL, 0, event, nsockets, NULL);
|
||||
if (evs < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
L9P_LOG(L9P_ERROR, "kevent(): %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < evs; i++) {
|
||||
struct sockaddr client_addr;
|
||||
socklen_t client_addr_len;
|
||||
int news = accept((int)event[i].ident, &client_addr,
|
||||
&client_addr_len);
|
||||
|
||||
if (news < 0) {
|
||||
L9P_LOG(L9P_WARNING, "accept(): %s",
|
||||
strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
l9p_socket_accept(server, news, &client_addr,
|
||||
client_addr_len);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
l9p_socket_accept(struct l9p_server *server, int conn_fd,
|
||||
struct sockaddr *client_addr, socklen_t client_addr_len)
|
||||
{
|
||||
struct l9p_socket_softc *sc;
|
||||
struct l9p_connection *conn;
|
||||
char host[NI_MAXHOST + 1];
|
||||
char serv[NI_MAXSERV + 1];
|
||||
int err;
|
||||
|
||||
err = getnameinfo(client_addr, client_addr_len, host, NI_MAXHOST, serv,
|
||||
NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
if (err != 0) {
|
||||
L9P_LOG(L9P_WARNING, "cannot look up client name: %s",
|
||||
gai_strerror(err));
|
||||
} else
|
||||
L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv);
|
||||
|
||||
if (l9p_connection_init(server, &conn) != 0) {
|
||||
L9P_LOG(L9P_ERROR, "cannot create new connection");
|
||||
return;
|
||||
}
|
||||
|
||||
sc = l9p_calloc(1, sizeof(*sc));
|
||||
sc->ls_conn = conn;
|
||||
sc->ls_fd = conn_fd;
|
||||
|
||||
l9p_connection_on_send_response(conn, l9p_socket_send_response, sc);
|
||||
l9p_connection_on_get_response_buffer(conn,
|
||||
l9p_socket_get_response_buffer, sc);
|
||||
|
||||
pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc);
|
||||
}
|
||||
|
||||
static void *
|
||||
l9p_socket_thread(void *arg)
|
||||
{
|
||||
struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
|
||||
struct iovec iov;
|
||||
void *buf;
|
||||
size_t length;
|
||||
|
||||
for (;;) {
|
||||
if (l9p_socket_readmsg(sc, &buf, &length) != 0)
|
||||
break;
|
||||
|
||||
iov.iov_base = buf;
|
||||
iov.iov_len = length;
|
||||
l9p_connection_recv(sc->ls_conn, &iov, 1, NULL);
|
||||
}
|
||||
|
||||
L9P_LOG(L9P_INFO, "connection closed");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size)
|
||||
{
|
||||
uint32_t msize;
|
||||
size_t toread;
|
||||
void *buffer;
|
||||
int fd = sc->ls_fd;
|
||||
|
||||
assert(fd > 0);
|
||||
|
||||
buffer = l9p_malloc(sizeof(uint32_t));
|
||||
|
||||
if (xread(fd, buffer, sizeof(uint32_t)) != sizeof(uint32_t)) {
|
||||
L9P_LOG(L9P_ERROR, "short read: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
msize = *(uint32_t *)buffer;
|
||||
toread = msize - sizeof(uint32_t);
|
||||
buffer = realloc(buffer, msize);
|
||||
|
||||
if (xread(fd, (char *)buffer + sizeof(uint32_t), toread) != (ssize_t)toread) {
|
||||
L9P_LOG(L9P_ERROR, "short read: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*size = msize;
|
||||
*buf = buffer;
|
||||
L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d",
|
||||
sc->ls_conn, buffer, msize);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov,
|
||||
size_t *niovp, void *arg __unused)
|
||||
{
|
||||
size_t size = req->lr_conn->lc_msize;
|
||||
void *buf;
|
||||
|
||||
buf = l9p_malloc(size);
|
||||
iov[0].iov_base = buf;
|
||||
iov[0].iov_len = size;
|
||||
|
||||
*niovp = 1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
l9p_socket_send_response(struct l9p_request *req __unused,
|
||||
const struct iovec *iov, const size_t niov __unused, const size_t iolen,
|
||||
void *arg)
|
||||
{
|
||||
struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg;
|
||||
|
||||
assert(sc->ls_fd > 0);
|
||||
|
||||
L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg,
|
||||
iov[0].iov_base, iolen);
|
||||
|
||||
if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != (int)iolen) {
|
||||
L9P_LOG(L9P_ERROR, "short write: %s", strerror(errno));
|
||||
return (-1);
|
||||
}
|
||||
|
||||
free(iov[0].iov_base);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
xread(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t done = 0;
|
||||
ssize_t ret;
|
||||
|
||||
while (done < count) {
|
||||
ret = read(fd, (char *)buf + done, count - done);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return ((ssize_t)done);
|
||||
|
||||
done += (size_t)ret;
|
||||
}
|
||||
|
||||
return ((ssize_t)done);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
xwrite(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t done = 0;
|
||||
ssize_t ret;
|
||||
|
||||
while (done < count) {
|
||||
ret = write(fd, (char *)buf + done, count - done);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
return ((ssize_t)done);
|
||||
|
||||
done += (size_t)ret;
|
||||
}
|
||||
|
||||
return ((ssize_t)done);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* 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_SOCKET_H
|
||||
#define LIB9P_SOCKET_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include "../lib9p.h"
|
||||
|
||||
int l9p_start_server(struct l9p_server *server, const char *host,
|
||||
const char *port);
|
||||
void l9p_socket_accept(struct l9p_server *server, int conn_fd,
|
||||
struct sockaddr *client_addr, socklen_t client_addr_len);
|
||||
|
||||
#endif /* LIB9P_SOCKET_H */
|
260
lib9p/utils.c
260
lib9p/utils.c
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/uio.h>
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sbuf.h>
|
||||
#else
|
||||
#include "sbuf/sbuf.h"
|
||||
#endif
|
||||
#include "lib9p.h"
|
||||
#include "fcall.h"
|
||||
|
||||
static const char *ftype_names[] = {
|
||||
"Tversion",
|
||||
"Rversion",
|
||||
"Tauth",
|
||||
"Rauth",
|
||||
"Tattach",
|
||||
"Rattach",
|
||||
"Terror",
|
||||
"Rerror",
|
||||
"Tflush",
|
||||
"Rflush",
|
||||
"Twalk",
|
||||
"Rwalk",
|
||||
"Topen",
|
||||
"Ropen",
|
||||
"Tcreate",
|
||||
"Rcreate",
|
||||
"Tread",
|
||||
"Rread",
|
||||
"Twrite",
|
||||
"Rwrite",
|
||||
"Tclunk",
|
||||
"Rclunk",
|
||||
"Tremove",
|
||||
"Rremove",
|
||||
"Tstat",
|
||||
"Rstat",
|
||||
"Twstat",
|
||||
"Rwstat"
|
||||
};
|
||||
|
||||
void
|
||||
l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2,
|
||||
size_t *niov2, size_t seek)
|
||||
{
|
||||
size_t remainder = 0;
|
||||
size_t left = seek;
|
||||
size_t i, j;
|
||||
|
||||
for (i = 0; i < niov1; i++) {
|
||||
size_t toseek = MIN(left, iov1[i].iov_len);
|
||||
left -= toseek;
|
||||
|
||||
if (toseek == iov1[i].iov_len)
|
||||
continue;
|
||||
|
||||
if (left == 0) {
|
||||
remainder = toseek;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = i; j < niov1; j++) {
|
||||
iov2[j - i].iov_base = (char *)iov1[j].iov_base + remainder;
|
||||
iov2[j - i].iov_len = iov1[j].iov_len - remainder;
|
||||
remainder = 0;
|
||||
}
|
||||
|
||||
*niov2 = j - i;
|
||||
}
|
||||
|
||||
size_t
|
||||
l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length)
|
||||
{
|
||||
size_t i, done = 0;
|
||||
|
||||
for (i = 0; i < niov; i++) {
|
||||
size_t toseek = MIN(length - done, iov[i].iov_len);
|
||||
done += toseek;
|
||||
|
||||
if (toseek < iov[i].iov_len) {
|
||||
iov[i].iov_len = toseek;
|
||||
return (i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (niov);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_describe_qid(struct l9p_qid *qid, struct sbuf *sb)
|
||||
{
|
||||
|
||||
assert(qid != NULL);
|
||||
assert(sb != NULL);
|
||||
|
||||
sbuf_printf(sb, "<0x%02x,%u,0x%016" PRIx64 ">", qid->type, qid->version,
|
||||
qid->path);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_describe_stat(struct l9p_stat *st, struct sbuf *sb)
|
||||
{
|
||||
|
||||
assert(st != NULL);
|
||||
assert(sb != NULL);
|
||||
|
||||
sbuf_printf(sb, "type=0x%04x dev=%d name=\"%s\" uid=\"%s\"",
|
||||
st->type, st->dev, st->name, st->uid);
|
||||
}
|
||||
|
||||
void
|
||||
l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version,
|
||||
struct sbuf *sb)
|
||||
{
|
||||
uint8_t type;
|
||||
int i;
|
||||
|
||||
assert(fcall != NULL);
|
||||
assert(sb != NULL);
|
||||
assert(version <= L9P_2000L && version >= L9P_2000);
|
||||
|
||||
type = fcall->hdr.type;
|
||||
|
||||
if (type < 100 || type > 127) {
|
||||
sbuf_printf(sb, "<unknown request %d> tag=%d", type,
|
||||
fcall->hdr.tag);
|
||||
return;
|
||||
}
|
||||
|
||||
sbuf_printf(sb, "%s tag=%d", ftype_names[type - L9P_TVERSION],
|
||||
fcall->hdr.tag);
|
||||
|
||||
switch (type) {
|
||||
case L9P_TVERSION:
|
||||
case L9P_RVERSION:
|
||||
sbuf_printf(sb, " version=\"%s\" msize=%d", fcall->version.version,
|
||||
fcall->version.msize);
|
||||
return;
|
||||
case L9P_TAUTH:
|
||||
sbuf_printf(sb, "afid=%d uname=\"%s\" aname=\"%s\"", fcall->hdr.fid,
|
||||
fcall->tauth.uname, fcall->tauth.aname);
|
||||
return;
|
||||
case L9P_TATTACH:
|
||||
sbuf_printf(sb, " fid=%d afid=%d uname=\"%s\" aname=\"%s\"",
|
||||
fcall->hdr.fid, fcall->tattach.afid, fcall->tattach.uname,
|
||||
fcall->tattach.aname);
|
||||
if (version >= L9P_2000U)
|
||||
sbuf_printf(sb, " n_uname=%d", fcall->tattach.n_uname);
|
||||
return;
|
||||
case L9P_RERROR:
|
||||
sbuf_printf(sb, " ename=\"%s\" errnum=%d", fcall->error.ename,
|
||||
fcall->error.errnum);
|
||||
return;
|
||||
case L9P_TFLUSH:
|
||||
sbuf_printf(sb, " oldtag=%d", fcall->tflush.oldtag);
|
||||
return;
|
||||
case L9P_TWALK:
|
||||
sbuf_printf(sb, " fid=%d newfid=%d wname=\"",
|
||||
fcall->hdr.fid, fcall->twalk.newfid);
|
||||
|
||||
for (i = 0; i < fcall->twalk.nwname; i++) {
|
||||
sbuf_printf(sb, "%s", fcall->twalk.wname[i]);
|
||||
if (i != fcall->twalk.nwname - 1)
|
||||
sbuf_printf(sb, "/");
|
||||
}
|
||||
sbuf_printf(sb, "\"");
|
||||
return;
|
||||
case L9P_RWALK:
|
||||
sbuf_printf(sb, " wqid=[");
|
||||
for (i = 0; i < fcall->rwalk.nwqid; i++) {
|
||||
l9p_describe_qid(&fcall->rwalk.wqid[i], sb);
|
||||
if (i != fcall->rwalk.nwqid - 1)
|
||||
sbuf_printf(sb, ",");
|
||||
}
|
||||
sbuf_printf(sb, "]");
|
||||
return;
|
||||
case L9P_TOPEN:
|
||||
sbuf_printf(sb, " fid=%d mode=%d", fcall->hdr.fid,
|
||||
fcall->tcreate.mode);
|
||||
|
||||
return;
|
||||
case L9P_ROPEN:
|
||||
sbuf_printf(sb, " qid=");
|
||||
l9p_describe_qid(&fcall->ropen.qid, sb);
|
||||
sbuf_printf(sb, " iounit=%d", fcall->ropen.iounit);
|
||||
return;
|
||||
case L9P_TCREATE:
|
||||
sbuf_printf(sb, " fid=%d name=\"%s\" perm=0x%08x mode=%d",
|
||||
fcall->hdr.fid, fcall->tcreate.name, fcall->tcreate.perm,
|
||||
fcall->tcreate.mode);
|
||||
return;
|
||||
case L9P_RCREATE:
|
||||
return;
|
||||
case L9P_TREAD:
|
||||
sbuf_printf(sb, " fid=%d offset=%" PRIu64 " count=%u", fcall->hdr.fid,
|
||||
fcall->io.offset, fcall->io.count);
|
||||
return;
|
||||
|
||||
case L9P_RREAD:
|
||||
case L9P_RWRITE:
|
||||
sbuf_printf(sb, " count=%d", fcall->io.count);
|
||||
return;
|
||||
case L9P_TWRITE:
|
||||
sbuf_printf(sb, " fid=%d offset=%" PRIu64 " count=%u", fcall->hdr.fid,
|
||||
fcall->io.offset, fcall->io.count);
|
||||
return;
|
||||
case L9P_TCLUNK:
|
||||
sbuf_printf(sb, " fid=%d ", fcall->hdr.fid);
|
||||
return;
|
||||
case L9P_TREMOVE:
|
||||
sbuf_printf(sb, " fid=%d", fcall->hdr.fid);
|
||||
return;
|
||||
case L9P_RREMOVE:
|
||||
return;
|
||||
case L9P_TSTAT:
|
||||
sbuf_printf(sb, " fid=%d", fcall->hdr.fid);
|
||||
return;
|
||||
case L9P_RSTAT:
|
||||
sbuf_printf(sb, " ");
|
||||
l9p_describe_stat(&fcall->rstat.stat, sb);
|
||||
return;
|
||||
case L9P_TWSTAT:
|
||||
sbuf_printf(sb, " fid=%d ", fcall->hdr.fid);
|
||||
l9p_describe_stat(&fcall->twstat.stat, sb);
|
||||
return;
|
||||
case L9P_RWSTAT:
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -221,7 +221,7 @@ vhpet_timer_interrupt(struct vhpet *vhpet, int n)
|
|||
lapic_intr_msi(vhpet->vm, vhpet->timer[n].msireg >> 32,
|
||||
vhpet->timer[n].msireg & 0xffffffff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pin = vhpet_timer_ioapic_pin(vhpet, n);
|
||||
if (pin == 0) {
|
||||
|
@ -291,7 +291,7 @@ vhpet_handler(void *a)
|
|||
callout_deactivate(callout);
|
||||
|
||||
if (!vhpet_counter_enabled(vhpet))
|
||||
xhyve_abort("vhpet(%p) callout with counter disabled\n", vhpet);
|
||||
xhyve_abort("vhpet(%p) callout with counter disabled\n", (void*)vhpet);
|
||||
|
||||
counter = vhpet_counter(vhpet, &now);
|
||||
vhpet_start_timer(vhpet, n, counter, now);
|
||||
|
@ -483,7 +483,7 @@ vhpet_mmio_write(void *vm, UNUSED int vcpuid, uint64_t gpa, uint64_t val, int si
|
|||
if ((offset & 0x4) != 0) {
|
||||
mask <<= 32;
|
||||
data <<= 32;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
VM_CTR2(vhpet->vm, "hpet invalid mmio write: "
|
||||
|
@ -638,7 +638,7 @@ vhpet_mmio_read(void *vm, UNUSED int vcpuid, uint64_t gpa, uint64_t *rval, int s
|
|||
|
||||
if (offset == HPET_CAPABILITIES || offset == HPET_CAPABILITIES + 4) {
|
||||
data = vhpet_capabilities();
|
||||
goto done;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (offset == HPET_CONFIG || offset == HPET_CONFIG + 4) {
|
||||
|
|
|
@ -136,7 +136,7 @@ usage(int code)
|
|||
" -h: help\n"
|
||||
" -H: vmexit from the guest on hlt\n"
|
||||
" -l: LPC device configuration\n"
|
||||
" -m: memory size in MB\n"
|
||||
" -m: memory size in MB, may be suffixed with one of K, M, G or T\n"
|
||||
" -M: print MAC address and exit if using vmnet\n"
|
||||
" -p: pin 'vcpu' to 'hostcpu'\n"
|
||||
" -P: vmexit from the guest on pause\n"
|
||||
|
|
Loading…
Add table
Reference in a new issue