Merge pull request #2 from stv0g/virtio-9p

Updating to latest master & added documentation, lib9p as a git submodule
This commit is contained in:
Jakub Klama 2016-04-02 22:10:50 +02:00
commit 200277a234
26 changed files with 41 additions and 3647 deletions

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "lib9p"]
path = lib9p
url = https://github.com/jceel/lib9p.git

View file

@ -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

@ -0,0 +1 @@
Subproject commit ddfdba40793f4bd2e988d4832cfadbf71ab7d024

33
lib9p/.gitignore vendored
View file

@ -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/

View file

@ -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.

View file

@ -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 $@

View file

@ -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>

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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");
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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;
}
}

View file

@ -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) {

View file

@ -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"