commit 6e7e6eba4610988e0e48c91992ac5b6fd3e82b0e
parent 1cd1e0ea108a56ccbf4b97f5e46a391f7ff8a76d
Author: Kris Maglione <kris@suckless.org>
Date: Sun, 23 May 2010 12:43:19 -0400
Cleanup the root dir a bit.
Diffstat:
49 files changed, 4354 insertions(+), 4336 deletions(-)
diff --git a/.hgignore b/.hgignore
@@ -0,0 +1,11 @@
+syntax: regexp
+(^|/)\.((.*\.)?sw.|depend|hgignore)$
+(^|/)(tags|mkfile|diff)$
+\.([oa]|out|o_pic|so|pyc|pyo|diff)$
+\.(diff|orig|rej|bak)$
+\.(aux|idx|ilg|ind|log|toc)$
+^(pkg|src)/
+/bak/
+syntax: glob
+config.local.mk
+*.pkg.tar.?z
diff --git a/Makefile b/Makefile
@@ -1,7 +1,7 @@
ROOT=.
include ${ROOT}/mk/hdr.mk
-DIRS = ${COMPONENTS} \
+DIRS = lib \
cmd \
include \
man
diff --git a/lib/Makefile b/lib/Makefile
@@ -0,0 +1,7 @@
+ROOT=..
+include $(ROOT)/mk/hdr.mk
+
+DIRS = $(COMPONENTS)
+
+include $(ROOT)/mk/dir.mk
+
diff --git a/lib/libixp/LICENSE b/lib/libixp/LICENSE
@@ -0,0 +1,21 @@
+
+© 2005-2006 Anselm R. Garbe <garbeam@gmail.com>
+© 2006-2009 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.
diff --git a/lib/libixp/Makefile b/lib/libixp/Makefile
@@ -0,0 +1,23 @@
+ROOT= ../..
+include $(ROOT)/mk/hdr.mk
+include $(ROOT)/mk/ixp.mk
+
+TARG = libixp
+
+OBJ = client \
+ convert \
+ error \
+ map \
+ message \
+ request \
+ rpc \
+ server \
+ srv_util \
+ socket \
+ thread \
+ timer \
+ transport \
+ util
+
+include ${ROOT}/mk/lib.mk
+
diff --git a/lib/libixp/README b/lib/libixp/README
@@ -0,0 +1,14 @@
+libixp - simple 9P client-/server-library
+===============================
+libixp is an extremly simple, stand-alone 9P library.
+
+
+Installation
+------------
+Edit config.mk to match your local setup. libixp is installed into
+/usr/local by default.
+
+Afterwards enter the following command to build and install libixp
+(if necessary as root):
+
+ $ make clean install
diff --git a/lib/libixp/client.c b/lib/libixp/client.c
@@ -0,0 +1,676 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+#define nelem(ary) (sizeof(ary) / sizeof(*ary))
+
+enum {
+ RootFid = 1,
+};
+
+static int
+min(int a, int b) {
+ if(a < b)
+ return a;
+ return b;
+}
+
+static IxpCFid*
+getfid(IxpClient *c) {
+ IxpCFid *f;
+
+ thread->lock(&c->lk);
+ f = c->freefid;
+ if(f != nil)
+ c->freefid = f->next;
+ else {
+ f = emallocz(sizeof *f);
+ f->client = c;
+ f->fid = ++c->lastfid;
+ thread->initmutex(&f->iolock);
+ }
+ f->next = nil;
+ f->open = 0;
+ thread->unlock(&c->lk);
+ return f;
+}
+
+static void
+putfid(IxpCFid *f) {
+ IxpClient *c;
+
+ c = f->client;
+ thread->lock(&c->lk);
+ if(f->fid == c->lastfid) {
+ c->lastfid--;
+ thread->mdestroy(&f->iolock);
+ free(f);
+ }else {
+ f->next = c->freefid;
+ c->freefid = f;
+ }
+ thread->unlock(&c->lk);
+}
+
+static int
+dofcall(IxpClient *c, Fcall *fcall) {
+ Fcall *ret;
+
+ ret = muxrpc(c, fcall);
+ if(ret == nil)
+ return 0;
+ if(ret->hdr.type == RError) {
+ werrstr("%s", ret->error.ename);
+ goto fail;
+ }
+ if(ret->hdr.type != (fcall->hdr.type^1)) {
+ werrstr("received mismatched fcall");
+ goto fail;
+ }
+ memcpy(fcall, ret, sizeof *fcall);
+ free(ret);
+ return 1;
+fail:
+ ixp_freefcall(fcall);
+ free(ret);
+ return 0;
+}
+
+/**
+ * Function: ixp_unmount
+ *
+ * Unmounts the client P<c> and frees its data structures.
+ */
+void
+ixp_unmount(IxpClient *c) {
+ IxpCFid *f;
+
+ shutdown(c->fd, SHUT_RDWR);
+ close(c->fd);
+
+ muxfree(c);
+
+ while((f = c->freefid)) {
+ c->freefid = f->next;
+ thread->mdestroy(&f->iolock);
+ free(f);
+ }
+ free(c->rmsg.data);
+ free(c->wmsg.data);
+ free(c);
+}
+
+static void
+allocmsg(IxpClient *c, int n) {
+ c->rmsg.size = n;
+ c->wmsg.size = n;
+ c->rmsg.data = erealloc(c->rmsg.data, n);
+ c->wmsg.data = erealloc(c->wmsg.data, n);
+}
+
+/**
+ * Function: ixp_mountfd
+ * Function: ixp_mount
+ * Function: ixp_nsmount
+ *
+ * Params:
+ * fd - A file descriptor which is already connected
+ * to a 9P server.
+ * address - An address (in Plan 9 resource fomat) at
+ * which to connect to a 9P server.
+ * name - The name of a socket in the process's canonical
+ * namespace directory.
+ *
+ * Initiate a 9P connection with the server at P<address>,
+ * connected to on P<fd>, or under the process's namespace
+ * directory as P<name>.
+ *
+ * Returns:
+ * A pointer to a new 9P client.
+ */
+
+IxpClient*
+ixp_mountfd(int fd) {
+ IxpClient *c;
+ Fcall fcall;
+
+ c = emallocz(sizeof *c);
+ c->fd = fd;
+
+ muxinit(c);
+
+ allocmsg(c, 256);
+ c->lastfid = RootFid;
+ /* Override tag matching on TVersion */
+ c->mintag = IXP_NOTAG;
+ c->maxtag = IXP_NOTAG+1;
+
+ fcall.hdr.type = TVersion;
+ fcall.version.msize = IXP_MAX_MSG;
+ fcall.version.version = IXP_VERSION;
+
+ if(dofcall(c, &fcall) == 0) {
+ ixp_unmount(c);
+ return nil;
+ }
+
+ if(strcmp(fcall.version.version, IXP_VERSION)
+ || fcall.version.msize > IXP_MAX_MSG) {
+ werrstr("bad 9P version response");
+ ixp_unmount(c);
+ return nil;
+ }
+
+ c->mintag = 0;
+ c->maxtag = 255;
+ c->msize = fcall.version.msize;
+
+ allocmsg(c, fcall.version.msize);
+ ixp_freefcall(&fcall);
+
+ fcall.hdr.type = TAttach;
+ fcall.hdr.fid = RootFid;
+ fcall.tattach.afid = IXP_NOFID;
+ fcall.tattach.uname = getenv("USER");
+ fcall.tattach.aname = "";
+ if(dofcall(c, &fcall) == 0) {
+ ixp_unmount(c);
+ return nil;
+ }
+
+ return c;
+}
+
+IxpClient*
+ixp_mount(const char *address) {
+ int fd;
+
+ fd = ixp_dial(address);
+ if(fd < 0)
+ return nil;
+ return ixp_mountfd(fd);
+}
+
+IxpClient*
+ixp_nsmount(const char *name) {
+ char *address;
+ IxpClient *c;
+
+ address = ixp_namespace();
+ if(address)
+ address = ixp_smprint("unix!%s/%s", address, name);
+ if(address == nil)
+ return nil;
+ c = ixp_mount(address);
+ free(address);
+ return c;
+}
+
+static IxpCFid*
+walk(IxpClient *c, const char *path) {
+ IxpCFid *f;
+ char *p;
+ Fcall fcall;
+ int n;
+
+ p = estrdup(path);
+ n = tokenize(fcall.twalk.wname, nelem(fcall.twalk.wname), p, '/');
+ f = getfid(c);
+
+ fcall.hdr.type = TWalk;
+ fcall.hdr.fid = RootFid;
+ fcall.twalk.nwname = n;
+ fcall.twalk.newfid = f->fid;
+ if(dofcall(c, &fcall) == 0)
+ goto fail;
+ if(fcall.rwalk.nwqid < n) {
+ werrstr("File does not exist");
+ if(fcall.rwalk.nwqid == 0)
+ werrstr("Protocol botch");
+ goto fail;
+ }
+
+ f->qid = fcall.rwalk.wqid[n-1];
+
+ ixp_freefcall(&fcall);
+ free(p);
+ return f;
+fail:
+ putfid(f);
+ free(p);
+ return nil;
+}
+
+static IxpCFid*
+walkdir(IxpClient *c, char *path, const char **rest) {
+ char *p;
+
+ p = path + strlen(path) - 1;
+ assert(p >= path);
+ while(*p == '/')
+ *p-- = '\0';
+
+ while((p > path) && (*p != '/'))
+ p--;
+ if(*p != '/') {
+ werrstr("bad path");
+ return nil;
+ }
+
+ *p++ = '\0';
+ *rest = p;
+ return walk(c, path);
+}
+
+static int
+clunk(IxpCFid *f) {
+ IxpClient *c;
+ Fcall fcall;
+ int ret;
+
+ c = f->client;
+
+ fcall.hdr.type = TClunk;
+ fcall.hdr.fid = f->fid;
+ ret = dofcall(c, &fcall);
+ if(ret)
+ putfid(f);
+ ixp_freefcall(&fcall);
+ return ret;
+}
+
+/**
+ * Function: ixp_remove
+ *
+ * Params:
+ * path - The path of the file to remove.
+ *
+ * Removes a file or directory from the remote server.
+ *
+ * Returns:
+ * ixp_remove returns 0 on failure, 1 on success.
+ */
+
+int
+ixp_remove(IxpClient *c, const char *path) {
+ Fcall fcall;
+ IxpCFid *f;
+ int ret;
+
+ if((f = walk(c, path)) == nil)
+ return 0;
+
+ fcall.hdr.type = TRemove;
+ fcall.hdr.fid = f->fid;;
+ ret = dofcall(c, &fcall);
+ ixp_freefcall(&fcall);
+ putfid(f);
+
+ return ret;
+}
+
+static void
+initfid(IxpCFid *f, Fcall *fcall) {
+ f->open = 1;
+ f->offset = 0;
+ f->iounit = fcall->ropen.iounit;
+ if(f->iounit == 0 || fcall->ropen.iounit > f->client->msize-24)
+ f->iounit = f->client->msize-24;
+ f->qid = fcall->ropen.qid;
+}
+
+/**
+ * Function: ixp_create
+ * Function: ixp_open
+ *
+ * Params:
+ * path - The path of the file to open or create.
+ * perm - The permissions with which to create the new
+ * file. These will be ANDed with those of the
+ * parent directory by the server.
+ * mode - The file's open mode.
+ *
+ * ixp_open and ixp_create each open a file at P<path>.
+ * P<mode> must include OREAD, OWRITE, or ORDWR, and may
+ * include any of the modes specified in 9pmodes(3).
+ * ixp_create, additionally, creates a file at P<path> if it
+ * doesn't already exist.
+ *
+ * Returns:
+ * A pointer on which to operate on the newly
+ * opened file.
+ */
+
+IxpCFid*
+ixp_create(IxpClient *c, const char *path, uint perm, uchar mode) {
+ Fcall fcall;
+ IxpCFid *f;
+ char *tpath;;
+
+ tpath = estrdup(path);
+
+ f = walkdir(c, tpath, &path);
+ if(f == nil)
+ goto done;
+
+ fcall.hdr.type = TCreate;
+ fcall.hdr.fid = f->fid;
+ fcall.tcreate.name = (char*)(uintptr_t)path;
+ fcall.tcreate.perm = perm;
+ fcall.tcreate.mode = mode;
+
+ if(dofcall(c, &fcall) == 0) {
+ clunk(f);
+ f = nil;
+ goto done;
+ }
+
+ initfid(f, &fcall);
+ f->mode = mode;
+
+ ixp_freefcall(&fcall);
+
+done:
+ free(tpath);
+ return f;
+}
+
+IxpCFid*
+ixp_open(IxpClient *c, const char *path, uchar mode) {
+ Fcall fcall;
+ IxpCFid *f;
+
+ f = walk(c, path);
+ if(f == nil)
+ return nil;
+
+ fcall.hdr.type = TOpen;
+ fcall.hdr.fid = f->fid;
+ fcall.topen.mode = mode;
+
+ if(dofcall(c, &fcall) == 0) {
+ clunk(f);
+ return nil;
+ }
+
+ initfid(f, &fcall);
+ f->mode = mode;
+
+ ixp_freefcall(&fcall);
+ return f;
+}
+
+/**
+ * Function: ixp_close
+ *
+ * Closes the file pointed to by P<f> and frees its
+ * associated data structures;
+ *
+ * Returns:
+ * Returns 1 on success, and zero on failure.
+ */
+
+int
+ixp_close(IxpCFid *f) {
+ return clunk(f);
+}
+
+static Stat*
+_stat(IxpClient *c, ulong fid) {
+ IxpMsg msg;
+ Fcall fcall;
+ Stat *stat;
+
+ fcall.hdr.type = TStat;
+ fcall.hdr.fid = fid;
+ if(dofcall(c, &fcall) == 0)
+ return nil;
+
+ msg = ixp_message((char*)fcall.rstat.stat, fcall.rstat.nstat, MsgUnpack);
+
+ stat = emalloc(sizeof *stat);
+ ixp_pstat(&msg, stat);
+ ixp_freefcall(&fcall);
+ if(msg.pos > msg.end) {
+ free(stat);
+ stat = nil;
+ }
+ return stat;
+}
+
+/**
+ * Function: ixp_stat
+ * Function: ixp_fstat
+ *
+ * Params:
+ * path - The path of the file to stat.
+ * f - A CFid of an open file to stat.
+ *
+ * Stats the file at P<path> or pointed to by P<f>.
+ *
+ * Returns:
+ * Returns a Stat structure, which must be freed by
+ * the caller with free(3).
+ *
+ * S<Stat>
+ */
+
+Stat*
+ixp_stat(IxpClient *c, const char *path) {
+ Stat *stat;
+ IxpCFid *f;
+
+ f = walk(c, path);
+ if(f == nil)
+ return nil;
+
+ stat = _stat(c, f->fid);
+ clunk(f);
+ return stat;
+}
+
+Stat*
+ixp_fstat(IxpCFid *f) {
+ return _stat(f->client, f->fid);
+}
+
+static long
+_pread(IxpCFid *f, char *buf, long count, vlong offset) {
+ Fcall fcall;
+ int n, len;
+
+ len = 0;
+ while(len < count) {
+ n = min(count-len, f->iounit);
+
+ fcall.hdr.type = TRead;
+ fcall.hdr.fid = f->fid;
+ fcall.tread.offset = offset;
+ fcall.tread.count = n;
+ if(dofcall(f->client, &fcall) == 0)
+ return -1;
+ if(fcall.rread.count > n)
+ return -1;
+
+ memcpy(buf+len, fcall.rread.data, fcall.rread.count);
+ offset += fcall.rread.count;
+ len += fcall.rread.count;
+
+ ixp_freefcall(&fcall);
+ if(fcall.rread.count < n)
+ break;
+ }
+ return len;
+}
+
+/**
+ * Function: ixp_read
+ * Function: ixp_pread
+ *
+ * Params:
+ * buf - A buffer in which to store the read data.
+ * count - The number of bytes to read.
+ * offset - The offset at which to begin reading.
+ *
+ * ixp_read and ixp_pread each read P<count> bytes of data
+ * from the file pointed to by P<f>, into P<buf>. ixp_read
+ * begins reading at its stored offset, and increments it by
+ * the number of bytes read. ixp_pread reads beginning at
+ * P<offset> and does not alter C<f>'s stored offset.
+ *
+ * Returns:
+ * These functions return the number of bytes read on
+ * success and -1 on failure.
+ */
+
+long
+ixp_read(IxpCFid *f, void *buf, long count) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pread(f, buf, count, f->offset);
+ if(n > 0)
+ f->offset += n;
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+long
+ixp_pread(IxpCFid *f, void *buf, long count, vlong offset) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pread(f, buf, count, offset);
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+static long
+_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
+ Fcall fcall;
+ int n, len;
+
+ len = 0;
+ do {
+ n = min(count-len, f->iounit);
+ fcall.hdr.type = TWrite;
+ fcall.hdr.fid = f->fid;
+ fcall.twrite.offset = offset;
+ fcall.twrite.data = (char*)buf + len;
+ fcall.twrite.count = n;
+ if(dofcall(f->client, &fcall) == 0)
+ return -1;
+
+ offset += fcall.rwrite.count;
+ len += fcall.rwrite.count;
+
+ ixp_freefcall(&fcall);
+ if(fcall.rwrite.count < n)
+ break;
+ } while(len < count);
+ return len;
+}
+
+/**
+ * Function: ixp_write
+ * Function: ixp_pwrite
+ *
+ * Params:
+ * buf - A buffer holding the contents to store.
+ * count - The number of bytes to store.
+ * offset - The offset at which to write the data.
+ *
+ * ixp_write and ixp_pwrite each write P<count> bytes of
+ * data stored in P<buf> to the file pointed to by C<f>.
+ * ixp_write writes its data at its stored offset, and
+ * increments it by P<count>. ixp_pwrite writes its data a
+ * P<offset> and does not alter C<f>'s stored offset.
+ *
+ * Returns:
+ * These functions return the number of bytes actually
+ * written. Any value less than P<count> must be considered
+ * a failure.
+ */
+
+long
+ixp_write(IxpCFid *f, const void *buf, long count) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pwrite(f, buf, count, f->offset);
+ if(n > 0)
+ f->offset += n;
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+long
+ixp_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
+ int n;
+
+ thread->lock(&f->iolock);
+ n = _pwrite(f, buf, count, offset);
+ thread->unlock(&f->iolock);
+ return n;
+}
+
+/**
+ * Function: ixp_vprint
+ * Function: ixp_print
+ * Variable: ixp_vsmprint
+ *
+ * Params:
+ * fmt - The string with which to format the data.
+ * ap - A va_list holding the arguments to the format
+ * string.
+ * ... - The arguments to the format string.
+ *
+ * These functions act like the standard formatted IO
+ * functions. They write the result of the formatting to the
+ * file pointed to by C<f>.
+ *
+ * V<ixp_vsmprint> may be set to a function which will
+ * format its arguments and return a null terminated string
+ * allocated with malloc(3).
+ *
+ * Returns:
+ * These functions return the number of bytes written.
+ * There is currently no way to detect failure.
+ */
+
+int
+ixp_vprint(IxpCFid *f, const char *fmt, va_list ap) {
+ char *buf;
+ int n;
+
+ buf = ixp_vsmprint(fmt, ap);
+ if(buf == nil)
+ return -1;
+
+ n = ixp_write(f, buf, strlen(buf));
+ free(buf);
+ return n;
+}
+
+int
+ixp_print(IxpCFid *f, const char *fmt, ...) {
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = ixp_vprint(f, fmt, ap);
+ va_end(ap);
+
+ return n;
+}
+
diff --git a/lib/libixp/convert.c b/lib/libixp/convert.c
@@ -0,0 +1,200 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ixp_local.h"
+
+enum {
+ SByte = 1,
+ SWord = 2,
+ SDWord = 4,
+ SQWord = 8,
+};
+
+static void
+ixp_puint(IxpMsg *msg, uint size, ulong *val) {
+ uchar *pos;
+ int v;
+
+ if(msg->pos + size <= msg->end) {
+ pos = (uchar*)msg->pos;
+ switch(msg->mode) {
+ case MsgPack:
+ v = *val;
+ switch(size) {
+ case SDWord:
+ pos[3] = v>>24;
+ pos[2] = v>>16;
+ case SWord:
+ pos[1] = v>>8;
+ case SByte:
+ pos[0] = v;
+ break;
+ }
+ case MsgUnpack:
+ v = 0;
+ switch(size) {
+ case SDWord:
+ v |= pos[3]<<24;
+ v |= pos[2]<<16;
+ case SWord:
+ v |= pos[1]<<8;
+ case SByte:
+ v |= pos[0];
+ break;
+ }
+ *val = v;
+ }
+ }
+ msg->pos += size;
+}
+
+void
+ixp_pu32(IxpMsg *msg, ulong *val) {
+ ixp_puint(msg, SDWord, val);
+}
+void
+ixp_pu8(IxpMsg *msg, uchar *val) {
+ ulong v;
+
+ v = *val;
+ ixp_puint(msg, SByte, &v);
+ *val = (uchar)v;
+}
+void
+ixp_pu16(IxpMsg *msg, ushort *val) {
+ ulong v;
+
+ v = *val;
+ ixp_puint(msg, SWord, &v);
+ *val = (ushort)v;
+}
+void
+ixp_pu64(IxpMsg *msg, uvlong *val) {
+ ulong vl, vb;
+
+ vl = (uint)*val;
+ vb = (uint)(*val>>32);
+ ixp_puint(msg, SDWord, &vl);
+ ixp_puint(msg, SDWord, &vb);
+ *val = vl | ((uvlong)vb<<32);
+}
+
+void
+ixp_pstring(IxpMsg *msg, char **s) {
+ ushort len;
+
+ if(msg->mode == MsgPack)
+ len = strlen(*s);
+ ixp_pu16(msg, &len);
+
+ if(msg->pos + len <= msg->end) {
+ if(msg->mode == MsgUnpack) {
+ *s = emalloc(len + 1);
+ memcpy(*s, msg->pos, len);
+ (*s)[len] = '\0';
+ }else
+ memcpy(msg->pos, *s, len);
+ }
+ msg->pos += len;
+}
+
+void
+ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
+ char *s;
+ uint i, size;
+ ushort len;
+
+ ixp_pu16(msg, num);
+ if(*num > IXP_MAX_WELEM) {
+ msg->pos = msg->end+1;
+ return;
+ }
+
+ SET(s);
+ if(msg->mode == MsgUnpack) {
+ s = msg->pos;
+ size = 0;
+ for(i=0; i < *num; i++) {
+ ixp_pu16(msg, &len);
+ msg->pos += len;
+ size += len;
+ if(msg->pos > msg->end)
+ return;
+ }
+ msg->pos = s;
+ size += *num;
+ s = emalloc(size);
+ }
+
+ for(i=0; i < *num; i++) {
+ if(msg->mode == MsgPack)
+ len = strlen(strings[i]);
+ ixp_pu16(msg, &len);
+
+ if(msg->mode == MsgUnpack) {
+ memcpy(s, msg->pos, len);
+ strings[i] = (char*)s;
+ s += len;
+ msg->pos += len;
+ *s++ = '\0';
+ }else
+ ixp_pdata(msg, &strings[i], len);
+ }
+}
+
+void
+ixp_pdata(IxpMsg *msg, char **data, uint len) {
+ if(msg->pos + len <= msg->end) {
+ if(msg->mode == MsgUnpack) {
+ *data = emalloc(len);
+ memcpy(*data, msg->pos, len);
+ }else
+ memcpy(msg->pos, *data, len);
+ }
+ msg->pos += len;
+}
+
+void
+ixp_pqid(IxpMsg *msg, Qid *qid) {
+ ixp_pu8(msg, &qid->type);
+ ixp_pu32(msg, &qid->version);
+ ixp_pu64(msg, &qid->path);
+}
+
+void
+ixp_pqids(IxpMsg *msg, ushort *num, Qid qid[]) {
+ int i;
+
+ ixp_pu16(msg, num);
+ if(*num > IXP_MAX_WELEM) {
+ msg->pos = msg->end+1;
+ return;
+ }
+
+ for(i = 0; i < *num; i++)
+ ixp_pqid(msg, &qid[i]);
+}
+
+void
+ixp_pstat(IxpMsg *msg, Stat *stat) {
+ ushort size;
+
+ if(msg->mode == MsgPack)
+ size = ixp_sizeof_stat(stat) - 2;
+
+ ixp_pu16(msg, &size);
+ ixp_pu16(msg, &stat->type);
+ ixp_pu32(msg, &stat->dev);
+ ixp_pqid(msg, &stat->qid);
+ ixp_pu32(msg, &stat->mode);
+ ixp_pu32(msg, &stat->atime);
+ ixp_pu32(msg, &stat->mtime);
+ ixp_pu64(msg, &stat->length);
+ ixp_pstring(msg, &stat->name);
+ ixp_pstring(msg, &stat->uid);
+ ixp_pstring(msg, &stat->gid);
+ ixp_pstring(msg, &stat->muid);
+}
diff --git a/lib/libixp/error.c b/lib/libixp/error.c
@@ -0,0 +1,103 @@
+/* Public Domain --Kris Maglione */
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "ixp_local.h"
+
+static int
+_vsnprint(char *buf, int n, const char *fmt, va_list ap) {
+ return vsnprintf(buf, n, fmt, ap);
+}
+
+static char*
+_vsmprint(const char *fmt, va_list ap) {
+ va_list al;
+ char *buf = "";
+ int n;
+
+ va_copy(al, ap);
+ n = vsnprintf(buf, 0, fmt, al);
+ va_end(al);
+
+ buf = malloc(++n);
+ if(buf)
+ vsnprintf(buf, n, fmt, ap);
+ return buf;
+}
+
+int (*ixp_vsnprint)(char*, int, const char*, va_list) = _vsnprint;
+char* (*ixp_vsmprint)(const char*, va_list) = _vsmprint;
+
+/* Approach to errno handling taken from Plan 9 Port. */
+enum {
+ EPLAN9 = 0x19283745,
+};
+
+/**
+ * Function: ixp_errbuf
+ * Function: ixp_errstr
+ * Function: ixp_rerrstr
+ * Function: ixp_werrstr
+ *
+ * Params:
+ * buf - The buffer to read and/or fill.
+ * n - The size of the buffer.
+ * fmt - A format string with which to write the * errstr.
+ * ... - Arguments to P<fmt>.
+ *
+ * These functions simulate Plan 9's errstr functionality.
+ * They replace errno in libixp. Note that these functions
+ * are not internationalized.
+ *
+ * F<ixp_errbuf> returns the errstr buffer for the current
+ * thread. F<ixp_rerrstr> fills P<buf> with the data from
+ * the current thread's error buffer, while F<ixp_errstr>
+ * exchanges P<buf>'s contents with those of the current
+ * thread's error buffer. F<ixp_werrstr> is takes a format
+ * string from which to construct an errstr.
+ *
+ * Returns:
+ * F<ixp_errbuf> returns the current thread's error
+ * string buffer.
+ */
+char*
+ixp_errbuf() {
+ char *errbuf;
+
+ errbuf = thread->errbuf();
+ if(errno == EINTR)
+ strncpy(errbuf, "interrupted", IXP_ERRMAX);
+ else if(errno != EPLAN9)
+ strncpy(errbuf, strerror(errno), IXP_ERRMAX);
+ return errbuf;
+}
+
+void
+errstr(char *buf, int n) {
+ char tmp[IXP_ERRMAX];
+
+ strncpy(tmp, buf, sizeof tmp);
+ rerrstr(buf, n);
+ strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
+ errno = EPLAN9;
+}
+
+void
+rerrstr(char *buf, int n) {
+ strncpy(buf, ixp_errbuf(), n);
+}
+
+void
+werrstr(const char *fmt, ...) {
+ char tmp[IXP_ERRMAX];
+ va_list ap;
+
+ va_start(ap, fmt);
+ ixp_vsnprint(tmp, sizeof tmp, fmt, ap);
+ va_end(ap);
+ strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
+ errno = EPLAN9;
+}
+
diff --git a/lib/libixp/map.c b/lib/libixp/map.c
@@ -0,0 +1,132 @@
+/* Written by Kris Maglione */
+/* Public domain */
+#include <stdlib.h>
+#include "ixp_local.h"
+
+/* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */
+
+struct MapEnt {
+ ulong hash;
+ const char* key;
+ void* val;
+ MapEnt* next;
+};
+
+MapEnt *NM;
+
+static void
+insert(MapEnt **e, ulong val, const char *key) {
+ MapEnt *te;
+
+ te = emallocz(sizeof *te);
+ te->hash = val;
+ te->key = key;
+ te->next = *e;
+ *e = te;
+}
+
+static MapEnt**
+map_getp(Map *map, ulong val, bool create, bool *exists) {
+ MapEnt **e;
+
+ e = &map->bucket[val%map->nhash];
+ for(; *e; e = &(*e)->next)
+ if((*e)->hash >= val) break;
+ if(exists)
+ *exists = *e && (*e)->hash == val;
+
+ if(*e == nil || (*e)->hash != val) {
+ if(create)
+ insert(e, val, nil);
+ else
+ e = &NM;
+ }
+ return e;
+}
+
+void
+ixp_mapfree(Map *map, void (*destroy)(void*)) {
+ int i;
+ MapEnt *e;
+
+ thread->wlock(&map->lock);
+ for(i=0; i < map->nhash; i++)
+ while((e = map->bucket[i])) {
+ map->bucket[i] = e->next;
+ if(destroy)
+ destroy(e->val);
+ free(e);
+ }
+ thread->wunlock(&map->lock);
+ thread->rwdestroy(&map->lock);
+}
+
+void
+ixp_mapexec(Map *map, void (*run)(void*, void*), void *context) {
+ int i;
+ MapEnt *e;
+
+ thread->rlock(&map->lock);
+ for(i=0; i < map->nhash; i++)
+ for(e=map->bucket[i]; e; e=e->next)
+ run(context, e->val);
+ thread->runlock(&map->lock);
+}
+
+void
+ixp_mapinit(Map *map, MapEnt **buckets, int nbuckets) {
+
+ map->bucket = buckets;
+ map->nhash = nbuckets;
+
+ thread->initrwlock(&map->lock);
+}
+
+bool
+ixp_mapinsert(Map *map, ulong key, void *val, bool overwrite) {
+ MapEnt *e;
+ bool existed, res;
+
+ res = true;
+ thread->wlock(&map->lock);
+ e = *map_getp(map, key, true, &existed);
+ if(existed && !overwrite)
+ res = false;
+ else
+ e->val = val;
+ thread->wunlock(&map->lock);
+ return res;
+}
+
+void*
+ixp_mapget(Map *map, ulong val) {
+ MapEnt *e;
+ void *res;
+
+ thread->rlock(&map->lock);
+ e = *map_getp(map, val, false, nil);
+ res = e ? e->val : nil;
+ thread->runlock(&map->lock);
+ return res;
+}
+
+void*
+ixp_maprm(Map *map, ulong val) {
+ MapEnt **e, *te;
+ void *ret;
+
+ ret = nil;
+ thread->wlock(&map->lock);
+ e = map_getp(map, val, false, nil);
+ if(*e) {
+ te = *e;
+ ret = te->val;
+ *e = te->next;
+ thread->wunlock(&map->lock);
+ free(te);
+ }
+ else
+ thread->wunlock(&map->lock);
+ return ret;
+}
+
diff --git a/lib/libixp/message.c b/lib/libixp/message.c
@@ -0,0 +1,205 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "ixp_local.h"
+
+enum {
+ SByte = 1,
+ SWord = 2,
+ SDWord = 4,
+ SQWord = 8,
+};
+
+#define SString(s) (SWord + strlen(s))
+enum {
+ SQid = SByte + SDWord + SQWord,
+};
+
+IxpMsg
+ixp_message(char *data, uint length, uint mode) {
+ IxpMsg m;
+
+ m.data = data;
+ m.pos = data;
+ m.end = data + length;
+ m.size = length;
+ m.mode = mode;
+ return m;
+}
+
+void
+ixp_freestat(Stat *s) {
+ free(s->name);
+ free(s->uid);
+ free(s->gid);
+ free(s->muid);
+ s->name = s->uid = s->gid = s->muid = nil;
+}
+
+void
+ixp_freefcall(Fcall *fcall) {
+ switch(fcall->hdr.type) {
+ case RStat:
+ free(fcall->rstat.stat);
+ fcall->rstat.stat = nil;
+ break;
+ case RRead:
+ free(fcall->rread.data);
+ fcall->rread.data = nil;
+ break;
+ case RVersion:
+ free(fcall->version.version);
+ fcall->version.version = nil;
+ break;
+ case RError:
+ free(fcall->error.ename);
+ fcall->error.ename = nil;
+ break;
+ }
+}
+
+ushort
+ixp_sizeof_stat(Stat * stat) {
+ return SWord /* size */
+ + SWord /* type */
+ + SDWord /* dev */
+ + SQid /* qid */
+ + 3 * SDWord /* mode, atime, mtime */
+ + SQWord /* length */
+ + SString(stat->name)
+ + SString(stat->uid)
+ + SString(stat->gid)
+ + SString(stat->muid);
+}
+
+void
+ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
+ ixp_pu8(msg, &fcall->hdr.type);
+ ixp_pu16(msg, &fcall->hdr.tag);
+
+ switch (fcall->hdr.type) {
+ case TVersion:
+ case RVersion:
+ ixp_pu32(msg, &fcall->version.msize);
+ ixp_pstring(msg, &fcall->version.version);
+ break;
+ case TAuth:
+ ixp_pu32(msg, &fcall->tauth.afid);
+ ixp_pstring(msg, &fcall->tauth.uname);
+ ixp_pstring(msg, &fcall->tauth.aname);
+ break;
+ case RAuth:
+ ixp_pqid(msg, &fcall->rauth.aqid);
+ break;
+ case RAttach:
+ ixp_pqid(msg, &fcall->rattach.qid);
+ break;
+ case TAttach:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu32(msg, &fcall->tattach.afid);
+ ixp_pstring(msg, &fcall->tattach.uname);
+ ixp_pstring(msg, &fcall->tattach.aname);
+ break;
+ case RError:
+ ixp_pstring(msg, &fcall->error.ename);
+ break;
+ case TFlush:
+ ixp_pu16(msg, &fcall->tflush.oldtag);
+ break;
+ case TWalk:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu32(msg, &fcall->twalk.newfid);
+ ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname);
+ break;
+ case RWalk:
+ ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
+ break;
+ case TOpen:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu8(msg, &fcall->topen.mode);
+ break;
+ case ROpen:
+ case RCreate:
+ ixp_pqid(msg, &fcall->ropen.qid);
+ ixp_pu32(msg, &fcall->ropen.iounit);
+ break;
+ case TCreate:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pstring(msg, &fcall->tcreate.name);
+ ixp_pu32(msg, &fcall->tcreate.perm);
+ ixp_pu8(msg, &fcall->tcreate.mode);
+ break;
+ case TRead:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu64(msg, &fcall->tread.offset);
+ ixp_pu32(msg, &fcall->tread.count);
+ break;
+ case RRead:
+ ixp_pu32(msg, &fcall->rread.count);
+ ixp_pdata(msg, &fcall->rread.data, fcall->rread.count);
+ break;
+ case TWrite:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu64(msg, &fcall->twrite.offset);
+ ixp_pu32(msg, &fcall->twrite.count);
+ ixp_pdata(msg, &fcall->twrite.data, fcall->twrite.count);
+ break;
+ case RWrite:
+ ixp_pu32(msg, &fcall->rwrite.count);
+ break;
+ case TClunk:
+ case TRemove:
+ case TStat:
+ ixp_pu32(msg, &fcall->hdr.fid);
+ break;
+ case RStat:
+ ixp_pu16(msg, &fcall->rstat.nstat);
+ ixp_pdata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat);
+ break;
+ case TWStat: {
+ ushort size;
+ ixp_pu32(msg, &fcall->hdr.fid);
+ ixp_pu16(msg, &size);
+ ixp_pstat(msg, &fcall->twstat.stat);
+ break;
+ }
+ }
+}
+
+uint
+ixp_fcall2msg(IxpMsg *msg, Fcall *fcall) {
+ ulong size;
+
+ msg->end = msg->data + msg->size;
+ msg->pos = msg->data + SDWord;
+ msg->mode = MsgPack;
+ ixp_pfcall(msg, fcall);
+
+ if(msg->pos > msg->end)
+ return 0;
+
+ msg->end = msg->pos;
+ size = msg->end - msg->data;
+
+ msg->pos = msg->data;
+ ixp_pu32(msg, &size);
+
+ msg->pos = msg->data;
+ return size;
+}
+
+uint
+ixp_msg2fcall(IxpMsg *msg, Fcall *fcall) {
+ msg->pos = msg->data + SDWord;
+ msg->mode = MsgUnpack;
+ ixp_pfcall(msg, fcall);
+
+ if(msg->pos > msg->end)
+ return 0;
+
+ return msg->pos - msg->data;
+}
+
diff --git a/lib/libixp/request.c b/lib/libixp/request.c
@@ -0,0 +1,550 @@
+/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include "ixp_local.h"
+
+static void handlereq(Ixp9Req *r);
+
+static void
+_printfcall(Fcall *f) {
+ USED(f);
+}
+void (*ixp_printfcall)(Fcall*) = _printfcall;
+
+static int
+min(int a, int b) {
+ if(a < b)
+ return a;
+ return b;
+}
+
+static char
+ Eduptag[] = "tag in use",
+ Edupfid[] = "fid in use",
+ Enofunc[] = "function not implemented",
+ Eopen[] = "fid is already open",
+ Enofile[] = "file does not exist",
+ Enoread[] = "file not open for reading",
+ Enofid[] = "fid does not exist",
+ Enotag[] = "tag does not exist",
+ Enotdir[] = "not a directory",
+ Eintr[] = "interrupted",
+ Eisdir[] = "cannot perform operation on a directory";
+
+enum {
+ TAG_BUCKETS = 61,
+ FID_BUCKETS = 61,
+};
+
+struct Ixp9Conn {
+ Map tagmap;
+ Map fidmap;
+ MapEnt* taghash[TAG_BUCKETS];
+ MapEnt* fidhash[FID_BUCKETS];
+ Ixp9Srv* srv;
+ IxpConn* conn;
+ IxpMutex rlock;
+ IxpMutex wlock;
+ IxpMsg rmsg;
+ IxpMsg wmsg;
+ int ref;
+};
+
+static void
+decref_p9conn(Ixp9Conn *p9conn) {
+ thread->lock(&p9conn->wlock);
+ if(--p9conn->ref > 0) {
+ thread->unlock(&p9conn->wlock);
+ return;
+ }
+ thread->unlock(&p9conn->wlock);
+
+ assert(p9conn->conn == nil);
+
+ thread->mdestroy(&p9conn->rlock);
+ thread->mdestroy(&p9conn->wlock);
+
+ ixp_mapfree(&p9conn->tagmap, nil);
+ ixp_mapfree(&p9conn->fidmap, nil);
+
+ free(p9conn->rmsg.data);
+ free(p9conn->wmsg.data);
+ free(p9conn);
+}
+
+static void*
+createfid(Map *map, int fid, Ixp9Conn *p9conn) {
+ Fid *f;
+
+ f = emallocz(sizeof *f);
+ p9conn->ref++;
+ f->conn = p9conn;
+ f->fid = fid;
+ f->omode = -1;
+ f->map = map;
+ if(ixp_mapinsert(map, fid, f, false))
+ return f;
+ free(f);
+ return nil;
+}
+
+static int
+destroyfid(Ixp9Conn *p9conn, ulong fid) {
+ Fid *f;
+
+ f = ixp_maprm(&p9conn->fidmap, fid);
+ if(f == nil)
+ return 0;
+
+ if(p9conn->srv->freefid)
+ p9conn->srv->freefid(f);
+
+ decref_p9conn(p9conn);
+ free(f);
+ return 1;
+}
+
+static void
+handlefcall(IxpConn *c) {
+ Fcall fcall = {0};
+ Ixp9Conn *p9conn;
+ Ixp9Req *req;
+
+ p9conn = c->aux;
+
+ thread->lock(&p9conn->rlock);
+ if(ixp_recvmsg(c->fd, &p9conn->rmsg) == 0)
+ goto Fail;
+ if(ixp_msg2fcall(&p9conn->rmsg, &fcall) == 0)
+ goto Fail;
+ thread->unlock(&p9conn->rlock);
+
+ req = emallocz(sizeof *req);
+ p9conn->ref++;
+ req->conn = p9conn;
+ req->srv = p9conn->srv;
+ req->ifcall = fcall;
+ p9conn->conn = c;
+
+ if(!ixp_mapinsert(&p9conn->tagmap, fcall.hdr.tag, req, false)) {
+ respond(req, Eduptag);
+ return;
+ }
+
+ handlereq(req);
+ return;
+
+Fail:
+ thread->unlock(&p9conn->rlock);
+ ixp_hangup(c);
+ return;
+}
+
+static void
+handlereq(Ixp9Req *r) {
+ Ixp9Conn *p9conn;
+ Ixp9Srv *srv;
+
+ p9conn = r->conn;
+ srv = p9conn->srv;
+
+ ixp_printfcall(&r->ifcall);
+
+ switch(r->ifcall.hdr.type) {
+ default:
+ respond(r, Enofunc);
+ break;
+ case TVersion:
+ if(!strcmp(r->ifcall.version.version, "9P"))
+ r->ofcall.version.version = "9P";
+ else if(!strcmp(r->ifcall.version.version, "9P2000"))
+ r->ofcall.version.version = "9P2000";
+ else
+ r->ofcall.version.version = "unknown";
+ r->ofcall.version.msize = r->ifcall.version.msize;
+ respond(r, nil);
+ break;
+ case TAttach:
+ if(!(r->fid = createfid(&p9conn->fidmap, r->ifcall.hdr.fid, p9conn))) {
+ respond(r, Edupfid);
+ return;
+ }
+ /* attach is a required function */
+ srv->attach(r);
+ break;
+ case TClunk:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(!srv->clunk) {
+ respond(r, nil);
+ return;
+ }
+ srv->clunk(r);
+ break;
+ case TFlush:
+ if(!(r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag))) {
+ respond(r, Enotag);
+ return;
+ }
+ if(!srv->flush) {
+ respond(r, Enofunc);
+ return;
+ }
+ srv->flush(r);
+ break;
+ case TCreate:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(r->fid->omode != -1) {
+ respond(r, Eopen);
+ return;
+ }
+ if(!(r->fid->qid.type&QTDIR)) {
+ respond(r, Enotdir);
+ return;
+ }
+ if(!p9conn->srv->create) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->create(r);
+ break;
+ case TOpen:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if((r->fid->qid.type&QTDIR) && (r->ifcall.topen.mode|P9_ORCLOSE) != (P9_OREAD|P9_ORCLOSE)) {
+ respond(r, Eisdir);
+ return;
+ }
+ r->ofcall.ropen.qid = r->fid->qid;
+ if(!p9conn->srv->open) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->open(r);
+ break;
+ case TRead:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(r->fid->omode == -1 || r->fid->omode == P9_OWRITE) {
+ respond(r, Enoread);
+ return;
+ }
+ if(!p9conn->srv->read) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->read(r);
+ break;
+ case TRemove:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(!p9conn->srv->remove) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->remove(r);
+ break;
+ case TStat:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(!p9conn->srv->stat) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->stat(r);
+ break;
+ case TWalk:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if(r->fid->omode != -1) {
+ respond(r, "cannot walk from an open fid");
+ return;
+ }
+ if(r->ifcall.twalk.nwname && !(r->fid->qid.type&QTDIR)) {
+ respond(r, Enotdir);
+ return;
+ }
+ if((r->ifcall.hdr.fid != r->ifcall.twalk.newfid)) {
+ if(!(r->newfid = createfid(&p9conn->fidmap, r->ifcall.twalk.newfid, p9conn))) {
+ respond(r, Edupfid);
+ return;
+ }
+ }else
+ r->newfid = r->fid;
+ if(!p9conn->srv->walk) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->walk(r);
+ break;
+ case TWrite:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if((r->fid->omode&3) != P9_OWRITE && (r->fid->omode&3) != P9_ORDWR) {
+ respond(r, "write on fid not opened for writing");
+ return;
+ }
+ if(!p9conn->srv->write) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->write(r);
+ break;
+ case TWStat:
+ if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
+ respond(r, Enofid);
+ return;
+ }
+ if((ushort)~r->ifcall.twstat.stat.type) {
+ respond(r, "wstat of type");
+ return;
+ }
+ if((uint)~r->ifcall.twstat.stat.dev) {
+ respond(r, "wstat of dev");
+ return;
+ }
+ if((uchar)~r->ifcall.twstat.stat.qid.type || (ulong)~r->ifcall.twstat.stat.qid.version || (uvlong)~r->ifcall.twstat.stat.qid.path) {
+ respond(r, "wstat of qid");
+ return;
+ }
+ if(r->ifcall.twstat.stat.muid && r->ifcall.twstat.stat.muid[0]) {
+ respond(r, "wstat of muid");
+ return;
+ }
+ if((ulong)~r->ifcall.twstat.stat.mode && ((r->ifcall.twstat.stat.mode&DMDIR)>>24) != r->fid->qid.type&QTDIR) {
+ respond(r, "wstat on DMDIR bit");
+ return;
+ }
+ if(!p9conn->srv->wstat) {
+ respond(r, Enofunc);
+ return;
+ }
+ p9conn->srv->wstat(r);
+ break;
+ /* Still to be implemented: auth */
+ }
+}
+
+void
+respond(Ixp9Req *r, const char *error) {
+ Ixp9Conn *p9conn;
+ int msize;
+
+ p9conn = r->conn;
+
+ switch(r->ifcall.hdr.type) {
+ default:
+ if(!error)
+ assert(!"Respond called on unsupported fcall type");
+ break;
+ case TVersion:
+ assert(error == nil);
+ free(r->ifcall.version.version);
+
+ thread->lock(&p9conn->rlock);
+ thread->lock(&p9conn->wlock);
+ msize = min(r->ofcall.version.msize, IXP_MAX_MSG);
+ p9conn->rmsg.data = erealloc(p9conn->rmsg.data, msize);
+ p9conn->wmsg.data = erealloc(p9conn->wmsg.data, msize);
+ p9conn->rmsg.size = msize;
+ p9conn->wmsg.size = msize;
+ thread->unlock(&p9conn->wlock);
+ thread->unlock(&p9conn->rlock);
+ r->ofcall.version.msize = msize;
+ break;
+ case TAttach:
+ if(error)
+ destroyfid(p9conn, r->fid->fid);
+ free(r->ifcall.tattach.uname);
+ free(r->ifcall.tattach.aname);
+ break;
+ case TOpen:
+ case TCreate:
+ if(!error) {
+ r->ofcall.ropen.iounit = p9conn->rmsg.size - 24;
+ r->fid->iounit = r->ofcall.ropen.iounit;
+ r->fid->omode = r->ifcall.topen.mode;
+ r->fid->qid = r->ofcall.ropen.qid;
+ }
+ free(r->ifcall.tcreate.name);
+ break;
+ case TWalk:
+ if(error || r->ofcall.rwalk.nwqid < r->ifcall.twalk.nwname) {
+ if(r->ifcall.hdr.fid != r->ifcall.twalk.newfid && r->newfid)
+ destroyfid(p9conn, r->newfid->fid);
+ if(!error && r->ofcall.rwalk.nwqid == 0)
+ error = Enofile;
+ }else{
+ if(r->ofcall.rwalk.nwqid == 0)
+ r->newfid->qid = r->fid->qid;
+ else
+ r->newfid->qid = r->ofcall.rwalk.wqid[r->ofcall.rwalk.nwqid-1];
+ }
+ free(*r->ifcall.twalk.wname);
+ break;
+ case TWrite:
+ free(r->ifcall.twrite.data);
+ break;
+ case TRemove:
+ if(r->fid)
+ destroyfid(p9conn, r->fid->fid);
+ break;
+ case TClunk:
+ if(r->fid)
+ destroyfid(p9conn, r->fid->fid);
+ break;
+ case TFlush:
+ if((r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag)))
+ respond(r->oldreq, Eintr);
+ break;
+ case TWStat:
+ ixp_freestat(&r->ifcall.twstat.stat);
+ break;
+ case TRead:
+ case TStat:
+ break;
+ /* Still to be implemented: auth */
+ }
+
+ r->ofcall.hdr.tag = r->ifcall.hdr.tag;
+
+ if(error == nil)
+ r->ofcall.hdr.type = r->ifcall.hdr.type + 1;
+ else {
+ r->ofcall.hdr.type = RError;
+ r->ofcall.error.ename = (char*)error;
+ }
+
+ ixp_printfcall(&r->ofcall);
+
+ ixp_maprm(&p9conn->tagmap, r->ifcall.hdr.tag);;
+
+ if(p9conn->conn) {
+ thread->lock(&p9conn->wlock);
+ msize = ixp_fcall2msg(&p9conn->wmsg, &r->ofcall);
+ if(ixp_sendmsg(p9conn->conn->fd, &p9conn->wmsg) != msize)
+ ixp_hangup(p9conn->conn);
+ thread->unlock(&p9conn->wlock);
+ }
+
+ switch(r->ofcall.hdr.type) {
+ case RStat:
+ free(r->ofcall.rstat.stat);
+ break;
+ case RRead:
+ free(r->ofcall.rread.data);
+ break;
+ }
+ free(r);
+ decref_p9conn(p9conn);
+}
+
+/* Flush a pending request */
+static void
+voidrequest(void *context, void *arg) {
+ Ixp9Req *orig_req, *flush_req;
+ Ixp9Conn *conn;
+
+ orig_req = arg;
+ conn = orig_req->conn;
+ conn->ref++;
+
+ flush_req = emallocz(sizeof *orig_req);
+ flush_req->ifcall.hdr.type = TFlush;
+ flush_req->ifcall.hdr.tag = IXP_NOTAG;
+ flush_req->ifcall.tflush.oldtag = orig_req->ifcall.hdr.tag;
+ flush_req->conn = conn;
+
+ flush_req->aux = *(void**)context;
+ *(void**)context = flush_req;
+}
+
+/* Clunk an open Fid */
+static void
+voidfid(void *context, void *arg) {
+ Ixp9Conn *p9conn;
+ Ixp9Req *clunk_req;
+ Fid *fid;
+
+ fid = arg;
+ p9conn = fid->conn;
+ p9conn->ref++;
+
+ clunk_req = emallocz(sizeof *clunk_req);
+ clunk_req->ifcall.hdr.type = TClunk;
+ clunk_req->ifcall.hdr.tag = IXP_NOTAG;
+ clunk_req->ifcall.hdr.fid = fid->fid;
+ clunk_req->fid = fid;
+ clunk_req->conn = p9conn;
+
+ clunk_req->aux = *(void**)context;
+ *(void**)context = clunk_req;
+}
+
+static void
+cleanupconn(IxpConn *c) {
+ Ixp9Conn *p9conn;
+ Ixp9Req *req, *r;
+
+ p9conn = c->aux;
+ p9conn->conn = nil;
+ req = nil;
+ if(p9conn->ref > 1) {
+ ixp_mapexec(&p9conn->fidmap, voidfid, &req);
+ ixp_mapexec(&p9conn->tagmap, voidrequest, &req);
+ }
+ while((r = req)) {
+ req = r->aux;
+ r->aux = nil;
+ handlereq(r);
+ }
+ decref_p9conn(p9conn);
+}
+
+/* Handle incoming 9P connections */
+void
+serve_9pcon(IxpConn *c) {
+ Ixp9Conn *p9conn;
+ int fd;
+
+ fd = accept(c->fd, nil, nil);
+ if(fd < 0)
+ return;
+
+ p9conn = emallocz(sizeof *p9conn);
+ p9conn->ref++;
+ p9conn->srv = c->aux;
+ p9conn->rmsg.size = 1024;
+ p9conn->wmsg.size = 1024;
+ p9conn->rmsg.data = emalloc(p9conn->rmsg.size);
+ p9conn->wmsg.data = emalloc(p9conn->wmsg.size);
+
+ ixp_mapinit(&p9conn->tagmap, p9conn->taghash, nelem(p9conn->taghash));
+ ixp_mapinit(&p9conn->fidmap, p9conn->fidhash, nelem(p9conn->fidhash));
+ thread->initmutex(&p9conn->rlock);
+ thread->initmutex(&p9conn->wlock);
+
+ ixp_listen(c->srv, fd, p9conn, handlefcall, cleanupconn);
+}
diff --git a/lib/libixp/rpc.c b/lib/libixp/rpc.c
@@ -0,0 +1,262 @@
+/* From Plan 9's libmux.
+ * Copyright (c) 2003 Russ Cox, Massachusetts Institute of Technology
+ * Distributed under the same terms as libixp.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "ixp_local.h"
+
+static int gettag(IxpClient*, IxpRpc*);
+static void puttag(IxpClient*, IxpRpc*);
+static void enqueue(IxpClient*, IxpRpc*);
+static void dequeue(IxpClient*, IxpRpc*);
+
+void
+muxinit(IxpClient *mux)
+{
+ mux->tagrend.mutex = &mux->lk;
+ mux->sleep.next = &mux->sleep;
+ mux->sleep.prev = &mux->sleep;
+ thread->initmutex(&mux->lk);
+ thread->initmutex(&mux->rlock);
+ thread->initmutex(&mux->wlock);
+ thread->initrendez(&mux->tagrend);
+}
+
+void
+muxfree(IxpClient *mux)
+{
+ thread->mdestroy(&mux->lk);
+ thread->mdestroy(&mux->rlock);
+ thread->mdestroy(&mux->wlock);
+ thread->rdestroy(&mux->tagrend);
+ free(mux->wait);
+}
+
+static void
+initrpc(IxpClient *mux, IxpRpc *r)
+{
+ r->mux = mux;
+ r->waiting = 1;
+ r->r.mutex = &mux->lk;
+ r->p = nil;
+ thread->initrendez(&r->r);
+}
+
+static void
+freemuxrpc(IxpRpc *r)
+{
+ thread->rdestroy(&r->r);
+}
+
+static int
+sendrpc(IxpRpc *r, Fcall *f)
+{
+ int ret;
+ IxpClient *mux;
+
+ ret = 0;
+ mux = r->mux;
+ /* assign the tag, add selves to response queue */
+ thread->lock(&mux->lk);
+ r->tag = gettag(mux, r);
+ f->hdr.tag = r->tag;
+ enqueue(mux, r);
+ thread->unlock(&mux->lk);
+
+ thread->lock(&mux->wlock);
+ if(!ixp_fcall2msg(&mux->wmsg, f) || !ixp_sendmsg(mux->fd, &mux->wmsg)) {
+ /* werrstr("settag/send tag %d: %r", tag); fprint(2, "%r\n"); */
+ thread->lock(&mux->lk);
+ dequeue(mux, r);
+ puttag(mux, r);
+ thread->unlock(&mux->lk);
+ ret = -1;
+ }
+ thread->unlock(&mux->wlock);
+ return ret;
+}
+
+static Fcall*
+muxrecv(IxpClient *mux)
+{
+ Fcall *f;
+
+ f = nil;
+ thread->lock(&mux->rlock);
+ if(ixp_recvmsg(mux->fd, &mux->rmsg) == 0)
+ goto fail;
+ f = emallocz(sizeof *f);
+ if(ixp_msg2fcall(&mux->rmsg, f) == 0) {
+ free(f);
+ f = nil;
+ }
+fail:
+ thread->unlock(&mux->rlock);
+ return f;
+}
+
+static void
+dispatchandqlock(IxpClient *mux, Fcall *f)
+{
+ int tag;
+ IxpRpc *r2;
+
+ tag = f->hdr.tag - mux->mintag;
+ thread->lock(&mux->lk);
+ /* hand packet to correct sleeper */
+ if(tag < 0 || tag >= mux->mwait) {
+ fprintf(stderr, "libixp: recieved unfeasible tag: %d (min: %d, max: %d)\n", f->hdr.tag, mux->mintag, mux->mintag+mux->mwait);
+ goto fail;
+ }
+ r2 = mux->wait[tag];
+ if(r2 == nil || r2->prev == nil) {
+ fprintf(stderr, "libixp: recieved message with bad tag\n");
+ goto fail;
+ }
+ r2->p = f;
+ dequeue(mux, r2);
+ thread->wake(&r2->r);
+ return;
+fail:
+ ixp_freefcall(f);
+ free(f);
+}
+
+static void
+electmuxer(IxpClient *mux)
+{
+ IxpRpc *rpc;
+
+ /* if there is anyone else sleeping, wake them to mux */
+ for(rpc=mux->sleep.next; rpc != &mux->sleep; rpc = rpc->next){
+ if(!rpc->async){
+ mux->muxer = rpc;
+ thread->wake(&rpc->r);
+ return;
+ }
+ }
+ mux->muxer = nil;
+}
+
+Fcall*
+muxrpc(IxpClient *mux, Fcall *tx)
+{
+ IxpRpc r;
+ Fcall *p;
+
+ initrpc(mux, &r);
+ if(sendrpc(&r, tx) < 0)
+ return nil;
+
+ thread->lock(&mux->lk);
+ /* wait for our packet */
+ while(mux->muxer && mux->muxer != &r && !r.p)
+ thread->sleep(&r.r);
+
+ /* if not done, there's no muxer; start muxing */
+ if(!r.p){
+ assert(mux->muxer == nil || mux->muxer == &r);
+ mux->muxer = &r;
+ while(!r.p){
+ thread->unlock(&mux->lk);
+ p = muxrecv(mux);
+ if(p == nil){
+ /* eof -- just give up and pass the buck */
+ thread->lock(&mux->lk);
+ dequeue(mux, &r);
+ break;
+ }
+ dispatchandqlock(mux, p);
+ }
+ electmuxer(mux);
+ }
+ p = r.p;
+ puttag(mux, &r);
+ thread->unlock(&mux->lk);
+ if(p == nil)
+ werrstr("unexpected eof");
+ return p;
+}
+
+static void
+enqueue(IxpClient *mux, IxpRpc *r)
+{
+ r->next = mux->sleep.next;
+ r->prev = &mux->sleep;
+ r->next->prev = r;
+ r->prev->next = r;
+}
+
+static void
+dequeue(IxpClient *mux, IxpRpc *r)
+{
+ r->next->prev = r->prev;
+ r->prev->next = r->next;
+ r->prev = nil;
+ r->next = nil;
+}
+
+static int
+gettag(IxpClient *mux, IxpRpc *r)
+{
+ int i, mw;
+ IxpRpc **w;
+
+ for(;;){
+ /* wait for a free tag */
+ while(mux->nwait == mux->mwait){
+ if(mux->mwait < mux->maxtag-mux->mintag){
+ mw = mux->mwait;
+ if(mw == 0)
+ mw = 1;
+ else
+ mw <<= 1;
+ w = realloc(mux->wait, mw * sizeof *w);
+ if(w == nil)
+ return -1;
+ memset(w+mux->mwait, 0, (mw-mux->mwait) * sizeof *w);
+ mux->wait = w;
+ mux->freetag = mux->mwait;
+ mux->mwait = mw;
+ break;
+ }
+ thread->sleep(&mux->tagrend);
+ }
+
+ i=mux->freetag;
+ if(mux->wait[i] == 0)
+ goto Found;
+ for(; i<mux->mwait; i++)
+ if(mux->wait[i] == 0)
+ goto Found;
+ for(i=0; i<mux->freetag; i++)
+ if(mux->wait[i] == 0)
+ goto Found;
+ /* should not fall out of while without free tag */
+ abort();
+ }
+
+Found:
+ mux->nwait++;
+ mux->wait[i] = r;
+ r->tag = i+mux->mintag;
+ return r->tag;
+}
+
+static void
+puttag(IxpClient *mux, IxpRpc *r)
+{
+ int i;
+
+ i = r->tag - mux->mintag;
+ assert(mux->wait[i] == r);
+ mux->wait[i] = nil;
+ mux->nwait--;
+ mux->freetag = i;
+ thread->wake(&mux->tagrend);
+ freemuxrpc(r);
+}
+
diff --git a/lib/libixp/server.c b/lib/libixp/server.c
@@ -0,0 +1,165 @@
+/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+/**
+ * Function: ixp_listen
+ *
+ * Params:
+ * fs - The file descriptor on which to listen.
+ * aux - A piece of data to store in the connection's
+ * T<IxpConn> data structure.
+ * read - The function to call when the connection has
+ * data available to read.
+ * close - A cleanup function to call when the
+ * connection is closed.
+ *
+ * Starts the server P<s> listening on P<fd>. The optional
+ * callbacks are called as described, with the connections
+ * T<IxpConn> data structure as their arguments.
+ *
+ * Returns:
+ * Returns the connection's new T<IxpConn> data
+ * structure.
+ *
+ * S<IxpConn>
+ */
+IxpConn*
+ixp_listen(IxpServer *s, int fd, void *aux,
+ void (*read)(IxpConn *c),
+ void (*close)(IxpConn *c)
+ ) {
+ IxpConn *c;
+
+ c = emallocz(sizeof *c);
+ c->fd = fd;
+ c->aux = aux;
+ c->srv = s;
+ c->read = read;
+ c->close = close;
+ c->next = s->conn;
+ s->conn = c;
+ return c;
+}
+
+/**
+ * Function: ixp_hangup
+ * Function: ixp_server_close
+ *
+ * ixp_hangup closes a connection, and stops the server
+ * listening on it. It calls the connection's close
+ * function, if it exists. ixp_server_close calls ixp_hangup
+ * on all of the connections on which the server is
+ * listening.
+ */
+
+void
+ixp_hangup(IxpConn *c) {
+ IxpServer *s;
+ IxpConn **tc;
+
+ s = c->srv;
+ for(tc=&s->conn; *tc; tc=&(*tc)->next)
+ if(*tc == c) break;
+ assert(*tc == c);
+
+ *tc = c->next;
+ c->closed = 1;
+ if(c->close)
+ c->close(c);
+ else
+ shutdown(c->fd, SHUT_RDWR);
+
+ close(c->fd);
+ free(c);
+}
+
+void
+ixp_server_close(IxpServer *s) {
+ IxpConn *c, *next;
+
+ for(c = s->conn; c; c = next) {
+ next = c->next;
+ ixp_hangup(c);
+ }
+}
+
+static void
+prepare_select(IxpServer *s) {
+ IxpConn *c;
+
+ FD_ZERO(&s->rd);
+ for(c = s->conn; c; c = c->next)
+ if(c->read) {
+ if(s->maxfd < c->fd)
+ s->maxfd = c->fd;
+ FD_SET(c->fd, &s->rd);
+ }
+}
+
+static void
+handle_conns(IxpServer *s) {
+ IxpConn *c, *n;
+ for(c = s->conn; c; c = n) {
+ n = c->next;
+ if(FD_ISSET(c->fd, &s->rd))
+ c->read(c);
+ }
+}
+
+/**
+ * Function: ixp_serverloop
+ *
+ * Enters the main loop of the server. Exits when
+ * P<s>->running becomes false, or when select(2) returns an
+ * error other than EINTR.
+ *
+ * S<IxpServer>
+ *
+ * Returns:
+ * Returns 0 when the loop exits normally, and 1 when
+ * it exits on error. V<errno> or the return value of
+ * ixp_errbuf(3) may be inspected.
+ *
+ */
+
+int
+ixp_serverloop(IxpServer *s) {
+ timeval *tvp;
+ timeval tv;
+ long timeout;
+ int r;
+
+ s->running = 1;
+ thread->initmutex(&s->lk);
+ while(s->running) {
+ if(s->preselect)
+ s->preselect(s);
+
+ tvp = nil;
+ timeout = ixp_nexttimer(s);
+ if(timeout > 0) {
+ tv.tv_sec = timeout/1000;
+ tv.tv_usec = timeout%1000 * 1000;
+ tvp = &tv;
+ }
+
+ prepare_select(s);
+ r = thread->select(s->maxfd + 1, &s->rd, 0, 0, tvp);
+ if(r < 0) {
+ if(errno == EINTR)
+ continue;
+ return 1;
+ }
+ handle_conns(s);
+ }
+ return 0;
+}
+
diff --git a/lib/libixp/socket.c b/lib/libixp/socket.c
@@ -0,0 +1,278 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
+ * See LICENSE file for license details.
+ */
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+/* Note: These functions modify the strings that they are passed.
+ * The lookup function duplicates the original string, so it is
+ * not modified.
+ */
+
+/* From FreeBSD's sys/su.h */
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+
+typedef struct addrinfo addrinfo;
+typedef struct sockaddr sockaddr;
+typedef struct sockaddr_un sockaddr_un;
+typedef struct sockaddr_in sockaddr_in;
+
+static char*
+get_port(char *addr) {
+ char *s;
+
+ s = strchr(addr, '!');
+ if(s == nil) {
+ werrstr("no port provided");
+ return nil;
+ }
+
+ *s++ = '\0';
+ if(*s == '\0') {
+ werrstr("invalid port number");
+ return nil;
+ }
+ return s;
+}
+
+static int
+sock_unix(char *address, sockaddr_un *sa, socklen_t *salen) {
+ int fd;
+
+ memset(sa, 0, sizeof *sa);
+
+ sa->sun_family = AF_UNIX;
+ strncpy(sa->sun_path, address, sizeof sa->sun_path);
+ *salen = SUN_LEN(sa);
+
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd < 0)
+ return -1;
+ return fd;
+}
+
+static int
+dial_unix(char *address) {
+ sockaddr_un sa;
+ socklen_t salen;
+ int fd;
+
+ fd = sock_unix(address, &sa, &salen);
+ if(fd == -1)
+ return fd;
+
+ if(connect(fd, (sockaddr*) &sa, salen)) {
+ close(fd);
+ return -1;
+ }
+ return fd;
+}
+
+static int
+announce_unix(char *file) {
+ const int yes = 1;
+ sockaddr_un sa;
+ socklen_t salen;
+ int fd;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ fd = sock_unix(file, &sa, &salen);
+ if(fd == -1)
+ return fd;
+
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof yes) < 0)
+ goto fail;
+
+ unlink(file);
+ if(bind(fd, (sockaddr*)&sa, salen) < 0)
+ goto fail;
+
+ chmod(file, S_IRWXU);
+ if(listen(fd, IXP_MAX_CACHE) < 0)
+ goto fail;
+
+ return fd;
+
+fail:
+ close(fd);
+ return -1;
+}
+
+static addrinfo*
+alookup(char *host, int announce) {
+ addrinfo hints, *ret;
+ char *port;
+ int err;
+
+ /* Truncates host at '!' */
+ port = get_port(host);
+ if(port == nil)
+ return nil;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+
+ if(announce) {
+ hints.ai_flags = AI_PASSIVE;
+ if(!strcmp(host, "*"))
+ host = nil;
+ }
+
+ err = getaddrinfo(host, port, &hints, &ret);
+ if(err) {
+ werrstr("getaddrinfo: %s", gai_strerror(err));
+ return nil;
+ }
+ return ret;
+}
+
+static int
+ai_socket(addrinfo *ai) {
+ return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+}
+
+static int
+dial_tcp(char *host) {
+ addrinfo *ai, *aip;
+ int fd;
+
+ aip = alookup(host, 0);
+ if(aip == nil)
+ return -1;
+
+ SET(fd);
+ for(ai = aip; ai; ai = ai->ai_next) {
+ fd = ai_socket(ai);
+ if(fd == -1) {
+ werrstr("socket: %s", strerror(errno));
+ continue;
+ }
+
+ if(connect(fd, ai->ai_addr, ai->ai_addrlen) == 0)
+ break;
+
+ werrstr("connect: %s", strerror(errno));
+ close(fd);
+ fd = -1;
+ }
+
+ freeaddrinfo(aip);
+ return fd;
+}
+
+static int
+announce_tcp(char *host) {
+ addrinfo *ai, *aip;
+ int fd;
+
+ aip = alookup(host, 1);
+ if(aip == nil)
+ return -1;
+
+ /* Probably don't need to loop */
+ SET(fd);
+ for(ai = aip; ai; ai = ai->ai_next) {
+ fd = ai_socket(ai);
+ if(fd == -1)
+ continue;
+
+ if(bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
+ goto fail;
+
+ if(listen(fd, IXP_MAX_CACHE) < 0)
+ goto fail;
+ break;
+ fail:
+ close(fd);
+ fd = -1;
+ }
+
+ freeaddrinfo(aip);
+ return fd;
+}
+
+typedef struct addrtab addrtab;
+static
+struct addrtab {
+ char *type;
+ int (*fn)(char*);
+} dtab[] = {
+ {"tcp", dial_tcp},
+ {"unix", dial_unix},
+ {0, 0}
+}, atab[] = {
+ {"tcp", announce_tcp},
+ {"unix", announce_unix},
+ {0, 0}
+};
+
+static int
+lookup(const char *address, addrtab *tab) {
+ char *addr, *type;
+ int ret;
+
+ ret = -1;
+ type = estrdup(address);
+
+ addr = strchr(type, '!');
+ if(addr == nil)
+ werrstr("no address type defined");
+ else {
+ *addr++ = '\0';
+ for(; tab->type; tab++)
+ if(strcmp(tab->type, type) == 0) break;
+ if(tab->type == nil)
+ werrstr("unsupported address type");
+ else
+ ret = tab->fn(addr);
+ }
+
+ free(type);
+ return ret;
+}
+
+/**
+ * Function: ixp_dial
+ * Function: ixp_announce
+ *
+ * Params:
+ * address - An address on which to connect or listen,
+ * specified in the Plan 9 resources
+ * specification format
+ * (<protocol>!address[!<port>])
+ *
+ * These functions hide some of the ugliness of Berkely
+ * Sockets. ixp_dial connects to the resource at P<address>,
+ * while ixp_announce begins listening on P<address>.
+ *
+ * Returns:
+ * These functions return file descriptors on success,
+ * and -1 on failure. ixp_errbuf(3) may be inspected on
+ * failure.
+ */
+
+int
+ixp_dial(const char *address) {
+ return lookup(address, dtab);
+}
+
+int
+ixp_announce(const char *address) {
+ return lookup(address, atab);
+}
+
diff --git a/lib/libixp/srv_util.c b/lib/libixp/srv_util.c
@@ -0,0 +1,457 @@
+/* Copyright ©2006-2008 Kris Maglione <fbsdaemon at gmail dot com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+typedef void* IxpFileIdU;
+
+static char
+ Enofile[] = "file not found";
+
+#include "ixp_srvutil.h"
+
+struct IxpQueue {
+ IxpQueue* link;
+ char* dat;
+ long len;
+};
+
+/* Macros */
+#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
+
+/* Global Vars */
+/***************/
+static IxpFileId* free_fileid;
+
+/* Utility Functions */
+/**
+ * Obtain an empty, reference counted IxpFileId struct.
+ */
+IxpFileId*
+ixp_srv_getfile(void) {
+ IxpFileId *file;
+ int i;
+
+ if(!free_fileid) {
+ i = 15;
+ file = emallocz(i * sizeof *file);
+ for(; i; i--) {
+ file->next = free_fileid;
+ free_fileid = file++;
+ }
+ }
+ file = free_fileid;
+ free_fileid = file->next;
+ file->p = nil;
+ file->volatil = 0;
+ file->nref = 1;
+ file->next = nil;
+ file->pending = false;
+ return file;
+}
+
+/**
+ * Decrease the reference count of the given IxpFileId,
+ * and push it onto the free list when it reaches 0;
+ */
+void
+ixp_srv_freefile(IxpFileId *f) {
+ if(--f->nref)
+ return;
+ free(f->tab.name);
+ f->next = free_fileid;
+ free_fileid = f;
+}
+
+/**
+ * Increase the reference count of every IxpFileId linked
+ * to 'f'.
+ */
+IxpFileId*
+ixp_srv_clonefiles(IxpFileId *f) {
+ IxpFileId *r;
+
+ r = emalloc(sizeof *r);
+ memcpy(r, f, sizeof *r);
+ r->tab.name = estrdup(r->tab.name);
+ r->nref = 1;
+ for(f=f->next; f; f=f->next)
+ assert(f->nref++);
+ return r;
+}
+
+void
+ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len) {
+
+ if(req->ifcall.io.offset >= len)
+ return;
+
+ len -= req->ifcall.io.offset;
+ if(len > req->ifcall.io.count)
+ len = req->ifcall.io.count;
+ req->ofcall.io.data = emalloc(len);
+ memcpy(req->ofcall.io.data, buf + req->ifcall.io.offset, len);
+ req->ofcall.io.count = len;
+}
+
+void
+ixp_srv_writebuf(Ixp9Req *req, char **buf, uint *len, uint max) {
+ IxpFileId *file;
+ char *p;
+ uint offset, count;
+
+ file = req->fid->aux;
+
+ offset = req->ifcall.io.offset;
+ if(file->tab.perm & DMAPPEND)
+ offset = *len;
+
+ if(offset > *len || req->ifcall.io.count == 0) {
+ req->ofcall.io.count = 0;
+ return;
+ }
+
+ count = req->ifcall.io.count;
+ if(max && (offset + count > max))
+ count = max - offset;
+
+ *len = offset + count;
+ if(max == 0)
+ *buf = erealloc(*buf, *len + 1);
+ p = *buf;
+
+ memcpy(p+offset, req->ifcall.io.data, count);
+ req->ofcall.io.count = count;
+ p[offset+count] = '\0';
+}
+
+/**
+ * Ensure that the data member of 'r' is null terminated,
+ * removing any new line from its end.
+ */
+void
+ixp_srv_data2cstring(Ixp9Req *req) {
+ char *p, *q;
+ uint i;
+
+ i = req->ifcall.io.count;
+ p = req->ifcall.io.data;
+ if(i && p[i - 1] == '\n')
+ i--;
+ q = memchr(p, '\0', i);
+ if(q)
+ i = q - p;
+
+ p = erealloc(req->ifcall.io.data, i+1);
+ p[i] = '\0';
+ req->ifcall.io.data = p;
+}
+
+char*
+ixp_srv_writectl(Ixp9Req *req, char* (*fn)(void*, IxpMsg*)) {
+ char *err, *s, *p, c;
+ IxpFileId *file;
+ IxpMsg msg;
+
+ file = req->fid->aux;
+
+ ixp_srv_data2cstring(req);
+ s = req->ifcall.io.data;
+
+ err = nil;
+ c = *s;
+ while(c != '\0') {
+ while(*s == '\n')
+ s++;
+ p = s;
+ while(*p != '\0' && *p != '\n')
+ p++;
+ c = *p;
+ *p = '\0';
+
+ msg = ixp_message(s, p-s, 0);
+ s = fn(file->p, &msg);
+ if(s)
+ err = s;
+ s = p + 1;
+ }
+ return err;
+}
+
+void
+ixp_pending_respond(Ixp9Req *req) {
+ IxpFileId *file;
+ IxpPendingLink *p;
+ IxpRequestLink *req_link;
+ IxpQueue *queue;
+
+ file = req->fid->aux;
+ assert(file->pending);
+ p = file->p;
+ if(p->queue) {
+ queue = p->queue;
+ p->queue = queue->link;
+ req->ofcall.io.data = queue->dat;
+ req->ofcall.io.count = queue->len;
+ if(req->aux) {
+ req_link = req->aux;
+ req_link->next->prev = req_link->prev;
+ req_link->prev->next = req_link->next;
+ free(req_link);
+ }
+ respond(req, nil);
+ free(queue);
+ }else {
+ req_link = emallocz(sizeof *req_link);
+ req_link->req = req;
+ req_link->next = &p->pending->req;
+ req_link->prev = req_link->next->prev;
+ req_link->next->prev = req_link;
+ req_link->prev->next = req_link;
+ req->aux = req_link;
+ }
+}
+
+void
+ixp_pending_write(IxpPending *pending, char *dat, long n) {
+ IxpRequestLink req_link;
+ IxpQueue **qp, *queue;
+ IxpPendingLink *pp;
+ IxpRequestLink *rp;
+
+ if(n == 0)
+ return;
+
+ if(pending->req.next == nil) {
+ pending->req.next = &pending->req;
+ pending->req.prev = &pending->req;
+ pending->fids.prev = &pending->fids;
+ pending->fids.next = &pending->fids;
+ }
+
+ for(pp=pending->fids.next; pp != &pending->fids; pp=pp->next) {
+ for(qp=&pp->queue; *qp; qp=&qp[0]->link)
+ ;
+ queue = emallocz(sizeof *queue);
+ queue->dat = emalloc(n);
+ memcpy(queue->dat, dat, n);
+ queue->len = n;
+ *qp = queue;
+ }
+
+ req_link.next = &req_link;
+ req_link.prev = &req_link;
+ if(pending->req.next != &pending->req) {
+ req_link.next = pending->req.next;
+ req_link.prev = pending->req.prev;
+ pending->req.prev = &pending->req;
+ pending->req.next = &pending->req;
+ }
+ req_link.prev->next = &req_link;
+ req_link.next->prev = &req_link;
+
+ while((rp = req_link.next) != &req_link)
+ ixp_pending_respond(rp->req);
+}
+
+void
+ixp_pending_pushfid(IxpPending *pending, IxpFid *fid) {
+ IxpPendingLink *pend_link;
+ IxpFileId *file;
+
+ if(pending->req.next == nil) {
+ pending->req.next = &pending->req;
+ pending->req.prev = &pending->req;
+ pending->fids.prev = &pending->fids;
+ pending->fids.next = &pending->fids;
+ }
+
+ file = fid->aux;
+ pend_link = emallocz(sizeof *pend_link);
+ pend_link->fid = fid;
+ pend_link->pending = pending;
+ pend_link->next = &pending->fids;
+ pend_link->prev = pend_link->next->prev;
+ pend_link->next->prev = pend_link;
+ pend_link->prev->next = pend_link;
+ file->pending = true;
+ file->p = pend_link;
+}
+
+static void
+pending_flush(Ixp9Req *req) {
+ IxpFileId *file;
+ IxpRequestLink *req_link;
+
+ file = req->fid->aux;
+ if(file->pending) {
+ req_link = req->aux;
+ if(req_link) {
+ req_link->prev->next = req_link->next;
+ req_link->next->prev = req_link->prev;
+ free(req_link);
+ }
+ }
+}
+
+void
+ixp_pending_flush(Ixp9Req *req) {
+
+ pending_flush(req->oldreq);
+}
+
+bool
+ixp_pending_clunk(Ixp9Req *req) {
+ IxpPending *pending;
+ IxpPendingLink *pend_link;
+ IxpRequestLink *req_link;
+ Ixp9Req *r;
+ IxpFileId *file;
+ IxpQueue *queue;
+ bool more;
+
+ file = req->fid->aux;
+ pend_link = file->p;
+
+ pending = pend_link->pending;
+ for(req_link=pending->req.next; req_link != &pending->req;) {
+ r = req_link->req;
+ req_link = req_link->next;
+ if(r->fid == pend_link->fid) {
+ pending_flush(r);
+ respond(r, "interrupted");
+ }
+ }
+
+ pend_link->prev->next = pend_link->next;
+ pend_link->next->prev = pend_link->prev;
+
+ while((queue = pend_link->queue)) {
+ pend_link->queue = queue->link;
+ free(queue->dat);
+ free(queue);
+ }
+ more = (pend_link->pending->fids.next == &pend_link->pending->fids);
+ free(pend_link);
+ respond(req, nil);
+ return more;
+}
+
+bool
+ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup) {
+ IxpFileId *tfile;
+ int ret;
+
+ if(!file->next)
+ return true;
+
+ ret = false;
+ if(ixp_srv_verifyfile(file->next, lookup)) {
+ tfile = lookup(file->next, file->tab.name);
+ if(tfile) {
+ if(!tfile->volatil || tfile->p == file->p)
+ ret = true;
+ ixp_srv_freefile(tfile);
+ }
+ }
+ return ret;
+}
+
+void
+ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(IxpStat*, IxpFileId*)) {
+ IxpMsg msg;
+ IxpFileId *file, *tfile;
+ IxpStat stat;
+ char *buf;
+ ulong size, n;
+ uvlong offset;
+
+ file = req->fid->aux;
+
+ size = req->ifcall.io.count;
+ if(size > req->fid->iounit)
+ size = req->fid->iounit;
+ buf = emallocz(size);
+ msg = ixp_message(buf, size, MsgPack);
+
+ file = lookup(file, nil);
+ tfile = file;
+ /* Note: The first file is ".", so we skip it. */
+ offset = 0;
+ for(file=file->next; file; file=file->next) {
+ dostat(&stat, file);
+ n = ixp_sizeof_stat(&stat);
+ if(offset >= req->ifcall.io.offset) {
+ if(size < n)
+ break;
+ ixp_pstat(&msg, &stat);
+ size -= n;
+ }
+ offset += n;
+ }
+ while((file = tfile)) {
+ tfile=tfile->next;
+ ixp_srv_freefile(file);
+ }
+ req->ofcall.io.count = msg.pos - msg.data;
+ req->ofcall.io.data = msg.data;
+ respond(req, nil);
+}
+
+void
+ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup) {
+ IxpFileId *file, *tfile;
+ int i;
+
+ file = ixp_srv_clonefiles(req->fid->aux);
+ for(i=0; i < req->ifcall.twalk.nwname; i++) {
+ if(!strcmp(req->ifcall.twalk.wname[i], "..")) {
+ if(file->next) {
+ tfile=file;
+ file=file->next;
+ ixp_srv_freefile(tfile);
+ }
+ }else{
+ tfile = lookup(file, req->ifcall.twalk.wname[i]);
+ if(!tfile)
+ break;
+ assert(!tfile->next);
+ if(strcmp(req->ifcall.twalk.wname[i], ".")) {
+ tfile->next = file;
+ file = tfile;
+ }
+ }
+ req->ofcall.rwalk.wqid[i].type = file->tab.qtype;
+ req->ofcall.rwalk.wqid[i].path = QID(file->tab.type, file->id);
+ }
+ /* There should be a way to do this on freefid() */
+ if(i < req->ifcall.twalk.nwname) {
+ while((tfile = file)) {
+ file=file->next;
+ ixp_srv_freefile(tfile);
+ }
+ respond(req, Enofile);
+ return;
+ }
+ /* Remove refs for req->fid if no new fid */
+ if(req->ifcall.hdr.fid == req->ifcall.twalk.newfid) {
+ tfile = req->fid->aux;
+ req->fid->aux = file;
+ while((file = tfile)) {
+ tfile = tfile->next;
+ ixp_srv_freefile(file);
+ }
+ }else
+ req->newfid->aux = file;
+ req->ofcall.rwalk.nwqid = i;
+ respond(req, nil);
+}
+
diff --git a/lib/libixp/thread.c b/lib/libixp/thread.c
@@ -0,0 +1,97 @@
+/* Public Domain --Kris Maglione */
+#include <unistd.h>
+#include "ixp_local.h"
+
+static IxpThread ixp_nothread;
+IxpThread*ixp_thread = &ixp_nothread;
+
+static char*
+errbuf(void) {
+ static char errbuf[IXP_ERRMAX];
+
+ return errbuf;
+}
+
+static void
+mvoid(IxpMutex *m) {
+ USED(m);
+ return;
+}
+
+static int
+mtrue(IxpMutex *m) {
+ USED(m);
+ return 1;
+}
+
+static int
+mfalse(IxpMutex *m) {
+ USED(m);
+ return 0;
+}
+
+static void
+rwvoid(IxpRWLock *rw) {
+ USED(rw);
+ return;
+}
+
+static int
+rwtrue(IxpRWLock *rw) {
+ USED(rw);
+ return 1;
+}
+
+static int
+rwfalse(IxpRWLock *m) {
+ USED(m);
+ return 0;
+}
+
+static void
+rvoid(IxpRendez *r) {
+ USED(r);
+ return;
+}
+
+static int
+rfalse(IxpRendez *r) {
+ USED(r);
+ return 0;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ USED(r);
+ eprint("rsleep called when not implemented\n");
+}
+
+static IxpThread ixp_nothread = {
+ /* RWLock */
+ .initrwlock = rwfalse,
+ .rlock = rwvoid,
+ .runlock = rwvoid,
+ .canrlock = rwtrue,
+ .wlock = rwvoid,
+ .wunlock = rwvoid,
+ .canwlock = rwtrue,
+ .rwdestroy = rwvoid,
+ /* Mutex */
+ .initmutex = mfalse,
+ .lock = mvoid,
+ .unlock = mvoid,
+ .canlock = mtrue,
+ .mdestroy = mvoid,
+ /* Rendez */
+ .initrendez = rfalse,
+ .sleep = rsleep,
+ .wake = rfalse,
+ .wakeall = rfalse,
+ .rdestroy = rvoid,
+ /* Other */
+ .errbuf = errbuf,
+ .read = read,
+ .write = write,
+ .select = select,
+};
+
diff --git a/lib/libixp/timer.c b/lib/libixp/timer.c
@@ -0,0 +1,139 @@
+/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include "ixp_local.h"
+
+/* This really needn't be threadsafe, as it has little use in
+ * threaded programs, but it is, nonetheless.
+ */
+
+static long lastid = 1;
+
+/**
+ * Function: ixp_msec
+ *
+ * Returns:
+ * Returns the time since the Epoch in milliseconds.
+ * Be aware that this may overflow.
+ */
+long
+ixp_msec(void) {
+ timeval tv;
+
+ if(gettimeofday(&tv, 0) < 0)
+ return -1;
+ return tv.tv_sec*1000 + tv.tv_usec/1000;
+}
+
+/**
+ * Function: ixp_settimer
+ *
+ * Params:
+ * msec - The timeout in milliseconds.
+ * fn - The function to call after P<msec> milliseconds
+ * have elapsed.
+ * aux - An arbitrary argument to pass to P<fn> when it
+ * is called.
+ *
+ * Initializes a callback-based timer to be triggerred after
+ * P<msec> milliseconds. The timer is passed its id number
+ * and the value of P<aux>.
+ *
+ * Returns:
+ * Returns the new timer's unique id number.
+ */
+long
+ixp_settimer(IxpServer *s, long msec, void (*fn)(long, void*), void *aux) {
+ Timer **tp;
+ Timer *t;
+ long time;
+
+ time = ixp_msec();
+ if(time == -1)
+ return -1;
+ msec += time;
+
+ t = emallocz(sizeof *t);
+ thread->lock(&s->lk);
+ t->id = lastid++;
+ t->msec = msec;
+ t->fn = fn;
+ t->aux = aux;
+
+ for(tp=&s->timer; *tp; tp=&tp[0]->link)
+ if(tp[0]->msec < msec)
+ break;
+ t->link = *tp;
+ *tp = t;
+ thread->unlock(&s->lk);
+ return t->id;
+}
+
+/**
+ * Function: ixp_unsettimer
+ *
+ * Params:
+ * id - The id number of the timer to void.
+ *
+ * Voids the timer identified by P<id>.
+ *
+ * Returns:
+ * Returns true if a timer was stopped, false
+ * otherwise.
+ */
+int
+ixp_unsettimer(IxpServer *s, long id) {
+ Timer **tp;
+ Timer *t;
+
+ thread->lock(&s->lk);
+ for(tp=&s->timer; (t=*tp); tp=&t->link)
+ if(t->id == id)
+ break;
+ if(t) {
+ *tp = t->link;
+ free(t);
+ }
+ thread->unlock(&s->lk);
+ return t != nil;
+}
+
+/**
+ * Function: ixp_nexttimer
+ *
+ * Triggers any timers whose timeouts have ellapsed. This is
+ * primarilly intended to be called from libixp's select
+ * loop.
+ *
+ * Returns:
+ * Returns the number of milliseconds until the next
+ * timer's timeout.
+ */
+long
+ixp_nexttimer(IxpServer *s) {
+ Timer *t;
+ long time, ret;
+
+ SET(time);
+ thread->lock(&s->lk);
+ while((t = s->timer)) {
+ time = ixp_msec();
+ if(t->msec > time)
+ break;
+ s->timer = t->link;
+
+ thread->unlock(&s->lk);
+ t->fn(t->id, t->aux);
+ free(t);
+ thread->lock(&s->lk);
+ }
+ ret = 0;
+ if(t)
+ ret = t->msec - time;
+ thread->unlock(&s->lk);
+ return ret;
+}
+
diff --git a/lib/libixp/transport.c b/lib/libixp/transport.c
@@ -0,0 +1,97 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+static int
+mread(int fd, IxpMsg *msg, uint count) {
+ int r, n;
+
+ n = msg->end - msg->pos;
+ if(n <= 0) {
+ werrstr("buffer full");
+ return -1;
+ }
+ if(n > count)
+ n = count;
+
+ r = thread->read(fd, msg->pos, n);
+ if(r > 0)
+ msg->pos += r;
+ return r;
+}
+
+static int
+readn(int fd, IxpMsg *msg, uint count) {
+ uint num;
+ int r;
+
+ num = count;
+ while(num > 0) {
+ r = mread(fd, msg, num);
+ if(r == -1 && errno == EINTR)
+ continue;
+ if(r == 0) {
+ werrstr("broken pipe: %s", ixp_errbuf());
+ return count - num;
+ }
+ num -= r;
+ }
+ return count - num;
+}
+
+uint
+ixp_sendmsg(int fd, IxpMsg *msg) {
+ int r;
+
+ msg->pos = msg->data;
+ while(msg->pos < msg->end) {
+ r = thread->write(fd, msg->pos, msg->end - msg->pos);
+ if(r < 1) {
+ if(errno == EINTR)
+ continue;
+ werrstr("broken pipe: %s", ixp_errbuf());
+ return 0;
+ }
+ msg->pos += r;
+ }
+ return msg->pos - msg->data;
+}
+
+uint
+ixp_recvmsg(int fd, IxpMsg *msg) {
+ enum { SSize = 4 };
+ ulong msize, size;
+
+ msg->mode = MsgUnpack;
+ msg->pos = msg->data;
+ msg->end = msg->data + msg->size;
+ if(readn(fd, msg, SSize) != SSize)
+ return 0;
+
+ msg->pos = msg->data;
+ ixp_pu32(msg, &msize);
+
+ size = msize - SSize;
+ if(size >= msg->end - msg->pos) {
+ werrstr("message too large");
+ return 0;
+ }
+ if(readn(fd, msg, size) != size) {
+ werrstr("message incomplete");
+ return 0;
+ }
+
+ msg->end = msg->pos;
+ return msize;
+}
+
diff --git a/lib/libixp/util.c b/lib/libixp/util.c
@@ -0,0 +1,240 @@
+/* Written by Kris Maglione <fbsdaemon at gmail dot com> */
+/* Public domain */
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pwd.h>
+#include "ixp_local.h"
+
+char*
+ixp_smprint(const char *fmt, ...) {
+ va_list ap;
+ char *s;
+
+ va_start(ap, fmt);
+ s = ixp_vsmprint(fmt, ap);
+ va_end(ap);
+ if(s == nil)
+ ixp_werrstr("no memory");
+ return s;
+}
+
+static char*
+_user(void) {
+ static char *user;
+ struct passwd *pw;
+
+ if(user == nil) {
+ pw = getpwuid(getuid());
+ if(pw)
+ user = strdup(pw->pw_name);
+ }
+ if(user == nil)
+ user = "none";
+ return user;
+}
+
+static int
+rmkdir(char *path, int mode) {
+ char *p;
+ int ret;
+ char c;
+
+ for(p = path+1; ; p++) {
+ c = *p;
+ if((c == '/') || (c == '\0')) {
+ *p = '\0';
+ ret = mkdir(path, mode);
+ if((ret == -1) && (errno != EEXIST)) {
+ ixp_werrstr("Can't create path '%s': %s", path, ixp_errbuf());
+ return 0;
+ }
+ *p = c;
+ }
+ if(c == '\0')
+ break;
+ }
+ return 1;
+}
+
+static char*
+ns_display(void) {
+ char *path, *disp;
+ struct stat st;
+
+ disp = getenv("DISPLAY");
+ if(disp == nil || disp[0] == '\0') {
+ ixp_werrstr("$DISPLAY is unset");
+ return nil;
+ }
+
+ disp = estrdup(disp);
+ path = &disp[strlen(disp) - 2];
+ if(path > disp && !strcmp(path, ".0"))
+ *path = '\0';
+
+ path = ixp_smprint("/tmp/ns.%s.%s", _user(), disp);
+ free(disp);
+
+ if(!rmkdir(path, 0700))
+ ;
+ else if(stat(path, &st))
+ ixp_werrstr("Can't stat ns_path '%s': %s", path, ixp_errbuf());
+ else if(getuid() != st.st_uid)
+ ixp_werrstr("ns_path '%s' exists but is not owned by you", path);
+ else if((st.st_mode & 077) && chmod(path, st.st_mode & ~077))
+ ixp_werrstr("Namespace path '%s' exists, but has wrong permissions: %s", path, ixp_errbuf());
+ else
+ return path;
+ free(path);
+ return nil;
+}
+
+/**
+ * Function: ixp_namespace
+ *
+ * Returns the path of the canonical 9p namespace directory.
+ * Either the value of $NAMESPACE, if it's set, or, roughly,
+ * /tmp/ns.${USER}.${DISPLAY:%.0=%}. In the latter case, the
+ * directory is created if it doesn't exist, and it is
+ * ensured to be owned by the current user, with no group or
+ * other permissions.
+ *
+ * Returns:
+ * A statically allocated string which must not be freed
+ * or altered by the caller. The same value is returned
+ * upon successive calls.
+ */
+/* Not especially threadsafe. */
+char*
+ixp_namespace(void) {
+ static char *namespace;
+
+ if(namespace == nil)
+ namespace = getenv("NAMESPACE");
+ if(namespace == nil)
+ namespace = ns_display();
+ return namespace;
+}
+
+void
+eprint(const char *fmt, ...) {
+ va_list ap;
+ int err;
+
+ err = errno;
+ fprintf(stderr, "libixp: fatal: ");
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ if(fmt[strlen(fmt)-1] == ':')
+ fprintf(stderr, " %s\n", strerror(err));
+ else
+ fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+/* Can't malloc */
+static void
+mfatal(char *name, uint size) {
+ const char
+ couldnot[] = "libixp: fatal: Could not ",
+ paren[] = "() ",
+ bytes[] = " bytes\n";
+ char sizestr[8];
+ int i;
+
+ i = sizeof sizestr;
+ do {
+ sizestr[--i] = '0' + (size%10);
+ size /= 10;
+ } while(size > 0);
+
+ write(1, couldnot, sizeof(couldnot)-1);
+ write(1, name, strlen(name));
+ write(1, paren, sizeof(paren)-1);
+ write(1, sizestr+i, sizeof(sizestr)-i);
+ write(1, bytes, sizeof(bytes)-1);
+
+ exit(1);
+}
+
+void*
+emalloc(uint size) {
+ void *ret = malloc(size);
+ if(!ret)
+ mfatal("malloc", size);
+ return ret;
+}
+
+void*
+emallocz(uint size) {
+ void *ret = emalloc(size);
+ memset(ret, 0, size);
+ return ret;
+}
+
+void*
+erealloc(void *ptr, uint size) {
+ void *ret = realloc(ptr, size);
+ if(!ret)
+ mfatal("realloc", size);
+ return ret;
+}
+
+char*
+estrdup(const char *str) {
+ void *ret = strdup(str);
+ if(!ret)
+ mfatal("strdup", strlen(str));
+ return ret;
+}
+
+uint
+tokenize(char *res[], uint reslen, char *str, char delim) {
+ char *s;
+ uint i;
+
+ i = 0;
+ s = str;
+ while(i < reslen && *s) {
+ while(*s == delim)
+ *(s++) = '\0';
+ if(*s)
+ res[i++] = s;
+ while(*s && *s != delim)
+ s++;
+ }
+ return i;
+}
+
+uint
+strlcat(char *dst, const char *src, uint size) {
+ const char *s;
+ char *d;
+ int n, len;
+
+ d = dst;
+ s = src;
+ n = size;
+ while(n-- > 0 && *d != '\0')
+ d++;
+ len = n;
+
+ while(*s != '\0' && n-- > 0)
+ *d++ = *s++;
+ while(*s++ != '\0')
+ n--;
+ if(len > 0)
+ *d = '\0';
+ return size - n - 1;
+}
+
diff --git a/lib/libixp_pthread/Makefile b/lib/libixp_pthread/Makefile
@@ -0,0 +1,10 @@
+ROOT= ../..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+TARG = libixp_pthread
+
+OBJ = thread_pthread
+
+include ${ROOT}/mk/lib.mk
+
diff --git a/lib/libixp_pthread/thread_pthread.c b/lib/libixp_pthread/thread_pthread.c
@@ -0,0 +1,184 @@
+/* Written by Kris Maglione <fbsdaemon@gmail.com> */
+/* Public domain */
+#define _XOPEN_SOURCE 600
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "ixp_local.h"
+
+static IxpThread ixp_pthread;
+static pthread_key_t errstr_k;
+
+int
+ixp_pthread_init() {
+ int ret;
+
+ ret = pthread_key_create(&errstr_k, free);
+ if(ret) {
+ werrstr("can't create TLS value: %s", ixp_errbuf());
+ return 1;
+ }
+
+ ixp_thread = &ixp_pthread;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ char *ret;
+
+ ret = pthread_getspecific(errstr_k);
+ if(ret == nil) {
+ ret = emallocz(IXP_ERRMAX);
+ pthread_setspecific(errstr_k, (void*)ret);
+ }
+ return ret;
+}
+
+static void
+mlock(IxpMutex *m) {
+ pthread_mutex_lock(m->aux);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return !pthread_mutex_trylock(m->aux);
+}
+
+static void
+munlock(IxpMutex *m) {
+ pthread_mutex_unlock(m->aux);
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ pthread_mutex_destroy(m->aux);
+ free(m->aux);
+}
+
+static int
+initmutex(IxpMutex *m) {
+ pthread_mutex_t *mutex;
+
+ mutex = emalloc(sizeof *mutex);
+ if(pthread_mutex_init(mutex, nil)) {
+ free(mutex);
+ return 1;
+ }
+
+ m->aux = mutex;
+ return 0;
+}
+
+static void
+rlock(IxpRWLock *rw) {
+ pthread_rwlock_rdlock(rw->aux);
+}
+
+static int
+canrlock(IxpRWLock *rw) {
+ return !pthread_rwlock_tryrdlock(rw->aux);
+}
+
+static void
+wlock(IxpRWLock *rw) {
+ pthread_rwlock_rdlock(rw->aux);
+}
+
+static int
+canwlock(IxpRWLock *rw) {
+ return !pthread_rwlock_tryrdlock(rw->aux);
+}
+
+static void
+rwunlock(IxpRWLock *rw) {
+ pthread_rwlock_unlock(rw->aux);
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ pthread_rwlock_destroy(rw->aux);
+ free(rw->aux);
+}
+
+static int
+initrwlock(IxpRWLock *rw) {
+ pthread_rwlock_t *rwlock;
+
+ rwlock = emalloc(sizeof *rwlock);
+ if(pthread_rwlock_init(rwlock, nil)) {
+ free(rwlock);
+ return 1;
+ }
+
+ rw->aux = rwlock;
+ return 0;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ pthread_cond_wait(r->aux, r->mutex->aux);
+}
+
+static int
+rwake(IxpRendez *r) {
+ pthread_cond_signal(r->aux);
+ return 0;
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ pthread_cond_broadcast(r->aux);
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ pthread_cond_destroy(r->aux);
+ free(r->aux);
+}
+
+static int
+initrendez(IxpRendez *r) {
+ pthread_cond_t *cond;
+
+ cond = emalloc(sizeof *cond);
+ if(pthread_cond_init(cond, nil)) {
+ free(cond);
+ return 1;
+ }
+
+ r->aux = cond;
+ return 0;
+}
+
+static IxpThread ixp_pthread = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = rlock,
+ .canrlock = canrlock,
+ .wlock = wlock,
+ .canwlock = canwlock,
+ .runlock = rwunlock,
+ .wunlock = rwunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = read,
+ .write = write,
+ .select = select,
+};
+
diff --git a/lib/libixp_rubythread/Makefile b/lib/libixp_rubythread/Makefile
@@ -0,0 +1,11 @@
+ROOT= ../..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+CFLAGS += ${RUBYINC}
+
+TARG = libixp_rubythread
+OBJ = thread_ruby
+
+include ${ROOT}/mk/lib.mk
+
diff --git a/lib/libixp_rubythread/thread_ruby.c b/lib/libixp_rubythread/thread_ruby.c
@@ -0,0 +1,281 @@
+/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
+ * See LICENSE file for license details.
+ */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ruby.h>
+#include "ixp_local.h"
+
+static IxpThread ixp_rthread;
+static char RWLock[];
+
+int
+ixp_rubyinit(void) {
+ rb_require("thread.rb");
+ rb_eval_string(RWLock);
+ ixp_thread = &ixp_rthread;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ static ID key;
+ volatile VALUE val;
+
+ if(key == 0L)
+ key = rb_intern("_ixp_errbuf");
+
+ val = rb_thread_local_aref(rb_thread_current(), key);
+ if(NIL_P(val)) {
+ val = rb_str_new(nil, IXP_ERRMAX);
+ rb_thread_local_aset(rb_thread_current(), key, val);
+ }
+
+ Check_Type(val, T_STRING);
+ return RSTRING(val)->ptr;
+}
+
+static void
+save(char *eval, void **place) {
+ *place = (void*)rb_eval_string(eval);
+ rb_gc_register_address((VALUE*)place);
+}
+
+static void
+unsave(void **place) {
+ rb_gc_unregister_address((VALUE*)place);
+}
+
+#define call(obj, meth, ...) rb_funcall((VALUE)obj, rb_intern(meth), __VA_ARGS__)
+
+/* Mutex */
+static int
+initmutex(IxpMutex *m) {
+ save("Mutex.new", &m->aux);
+ return 0;
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ unsave(&m->aux);
+}
+
+static void
+mlock(IxpMutex *m) {
+ call(m->aux, "lock", 0);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return call(m->aux, "trylock", 0);
+}
+
+static void
+munlock(IxpMutex *m) {
+ call(m->aux, "unlock", 0);
+}
+
+/* RWLock */
+static int
+initrwlock(IxpRWLock *rw) {
+ save("RWLock.new", &rw->aux);
+ return 0;
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ unsave(&rw->aux);
+}
+
+static void
+rlock(IxpRWLock *rw) {
+ call(rw->aux, "rdlock", 0);
+}
+
+static int
+canrlock(IxpRWLock *rw) {
+ return call(rw->aux, "tryrdlock", 0) == Qtrue;
+}
+
+static void
+wlock(IxpRWLock *rw) {
+ call(rw->aux, "wrlock", 0);
+}
+
+static int
+canwlock(IxpRWLock *rw) {
+ return call(rw->aux, "trywrlock", 0) == Qtrue;
+}
+
+static void
+rwunlock(IxpRWLock *rw) {
+ call(rw->aux, "unlock", 0);
+}
+
+/* Rendez */
+static int
+initrendez(IxpRendez *r) {
+ save("ConditionVariable.new", &r->aux);
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ unsave(&r->aux);
+}
+
+static void
+rsleep(IxpRendez *r) {
+ call(r->aux, "wait", 1, (VALUE)r->mutex->aux);
+}
+
+static int
+rwake(IxpRendez *r) {
+ call(r->aux, "signal", 0);
+ return 0;
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ call(r->aux, "broadcast", 0);
+ return 0;
+}
+
+/* Yielding IO */
+static ssize_t
+_read(int fd, void *buf, size_t size) {
+ int n;
+
+ rb_thread_wait_fd(fd);
+ n = read(fd, buf, size);
+
+ if(n < 0 && errno == EINTR)
+ rb_thread_schedule();
+ return n;
+}
+
+static ssize_t
+_write(int fd, const void *buf, size_t size) {
+ int n;
+
+ rb_thread_fd_writable(fd);
+ n = write(fd, buf, size);
+
+ if(n < 0 && errno == EINTR)
+ rb_thread_schedule();
+ return n;
+}
+
+static IxpThread ixp_rthread = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = rlock,
+ .canrlock = canrlock,
+ .wlock = wlock,
+ .canwlock = canwlock,
+ .runlock = rwunlock,
+ .wunlock = rwunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = _read,
+ .write = _write,
+ .select = rb_thread_select,
+};
+
+static char RWLock[] =
+ "class RWLock \n"
+ " def initialize \n"
+ " @rdqueue = [] \n"
+ " @wrqueue = [] \n"
+ " @wrheld = nil \n"
+ " @rdheld = [] \n"
+ " end \n"
+ " \n"
+ " def rdlock \n"
+ " cr = Thread.critical \n"
+ " while (Thread.critical = true; @wrheld != nil && @rwheld != Thread.current)\n"
+ " @rdqueue.push Thread.current \n"
+ " Thread.stop \n"
+ " end \n"
+ " @wrheld = nil \n"
+ " @rdheld.push Thread.current \n"
+ " \n"
+ " @rdqueue.each {|t| t.wakeup} \n"
+ " Thread.critical = cr \n"
+ " self \n"
+ " end \n"
+ " \n"
+ " def wrlock \n"
+ " cr = Thread.critical \n"
+ " while (Thread.critical = true; \n"
+ " !@rdheld.empty? || (@wrheld != Thread.current && @wrheld != nil)) \n"
+ " @wrqueue.push Thread.current \n"
+ " Thread.stop \n"
+ " end \n"
+ " @wrheld = Thread.current \n"
+ " Thread.critical = cr \n"
+ " self \n"
+ " end \n"
+ " \n"
+ " \n"
+ " def tryrdlock \n"
+ " cr = Thread.critical \n"
+ " if @wrheld == nil \n"
+ " rdlock \n"
+ " true \n"
+ " else \n"
+ " false \n"
+ " end \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ " \n"
+ " def trywrlock \n"
+ " cr = Thread.critical \n"
+ " if @wrheld == nil && @rdheld.empty? \n"
+ " wrlock \n"
+ " true \n"
+ " else \n"
+ " false \n"
+ " end \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ " \n"
+ " def unlock \n"
+ " cr = Thread.critical \n"
+ " Thread.critical = true \n"
+ " \n"
+ " if @rdheld.include?(Thread.current) \n"
+ " @rdheld.remove!(Thread.current) \n"
+ " raise if @wrheld \n"
+ " elsif @rwheld != Thread.current \n"
+ " raise \n"
+ " end \n"
+ " \n"
+ " @wrheld = nil \n"
+ " if !@rwqueue.empty? && @rdheld.empty? \n"
+ " @wrheld = @wrqueue.shift \n"
+ " elsif !@rdqueue.empty \n"
+ " @wrheld = @rdqueue.shift \n"
+ " end \n"
+ " @wrheld.wakeup if @wrheld \n"
+ " ensure \n"
+ " Thread.critical = cr \n"
+ " end \n"
+ "end \n";
+
diff --git a/lib/libixp_task/Makefile b/lib/libixp_task/Makefile
@@ -0,0 +1,11 @@
+ROOT= ../..
+include ${ROOT}/mk/hdr.mk
+include ${ROOT}/mk/ixp.mk
+
+CFLAGS += ${TASKINC}
+
+TARG = libixp_task
+OBJ = thread_task
+
+include ${ROOT}/mk/lib.mk
+
diff --git a/lib/libixp_task/thread_task.c b/lib/libixp_task/thread_task.c
@@ -0,0 +1,179 @@
+/* Written by Kris Maglione <fbsdaemon@gmail.com> */
+/* Public domain */
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <task.h>
+#include "ixp_local.h"
+
+static IxpThread ixp_task;
+
+int
+ixp_taskinit() {
+ ixp_thread = &ixp_task;
+ return 0;
+}
+
+static char*
+errbuf(void) {
+ void **p;
+
+ p = taskdata();
+ if(*p == nil)
+ *p = emallocz(IXP_ERRMAX);
+ return *p;
+}
+
+/* Mutex */
+static int
+initmutex(IxpMutex *m) {
+ m->aux = emallocz(sizeof(QLock));
+ return 0;
+}
+
+static void
+mdestroy(IxpMutex *m) {
+ free(m->aux);
+ m->aux = nil;
+}
+
+static void
+mlock(IxpMutex *m) {
+ qlock(m->aux);
+}
+
+static int
+mcanlock(IxpMutex *m) {
+ return canqlock(m->aux);
+}
+
+static void
+munlock(IxpMutex *m) {
+ qunlock(m->aux);
+}
+
+/* RWLock */
+static int
+initrwlock(IxpRWLock *rw) {
+ rw->aux = emallocz(sizeof(RWLock));
+ return 0;
+}
+
+static void
+rwdestroy(IxpRWLock *rw) {
+ free(rw->aux);
+ rw->aux = nil;
+}
+
+static void
+_rlock(IxpRWLock *rw) {
+ rlock(rw->aux);
+}
+
+static int
+_canrlock(IxpRWLock *rw) {
+ return canrlock(rw->aux);
+}
+
+static void
+_wlock(IxpRWLock *rw) {
+ wlock(rw->aux);
+}
+
+static int
+_canwlock(IxpRWLock *rw) {
+ return canwlock(rw->aux);
+}
+
+static void
+_runlock(IxpRWLock *rw) {
+ runlock(rw->aux);
+}
+
+static void
+_wunlock(IxpRWLock *rw) {
+ wunlock(rw->aux);
+}
+
+/* Rendez */
+static int
+initrendez(IxpRendez *r) {
+ r->aux = emallocz(sizeof(Rendez));
+ return 0;
+}
+
+static void
+rdestroy(IxpRendez *r) {
+ free(r->aux);
+ r->aux = nil;
+}
+
+static void
+rsleep(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ tasksleep(rz);
+}
+
+static int
+rwake(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ return taskwakeup(rz);
+}
+
+static int
+rwakeall(IxpRendez *r) {
+ Rendez *rz;
+
+ rz = r->aux;
+ rz->l = r->mutex->aux;
+ return taskwakeupall(rz);
+}
+
+/* Yielding IO */
+static ssize_t
+_read(int fd, void *buf, size_t size) {
+ fdnoblock(fd);
+ return fdread(fd, buf, size);
+}
+
+static ssize_t
+_write(int fd, const void *buf, size_t size) {
+ fdnoblock(fd);
+ return fdwrite(fd, (void*)buf, size);
+}
+
+static IxpThread ixp_task = {
+ /* Mutex */
+ .initmutex = initmutex,
+ .lock = mlock,
+ .canlock = mcanlock,
+ .unlock = munlock,
+ .mdestroy = mdestroy,
+ /* RWLock */
+ .initrwlock = initrwlock,
+ .rlock = _rlock,
+ .canrlock = _canrlock,
+ .wlock = _wlock,
+ .canwlock = _canwlock,
+ .runlock = _runlock,
+ .wunlock = _wunlock,
+ .rwdestroy = rwdestroy,
+ /* Rendez */
+ .initrendez = initrendez,
+ .sleep = rsleep,
+ .wake = rwake,
+ .wakeall = rwakeall,
+ .rdestroy = rdestroy,
+ /* Other */
+ .errbuf = errbuf,
+ .read = _read,
+ .write = _write,
+ .select = select, /* wrong */
+};
+
diff --git a/libixp/LICENSE b/libixp/LICENSE
@@ -1,21 +0,0 @@
-
-© 2005-2006 Anselm R. Garbe <garbeam@gmail.com>
-© 2006-2009 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.
diff --git a/libixp/Makefile b/libixp/Makefile
@@ -1,23 +0,0 @@
-ROOT= ..
-include $(ROOT)/mk/hdr.mk
-include $(ROOT)/mk/ixp.mk
-
-TARG = libixp
-
-OBJ = client \
- convert \
- error \
- map \
- message \
- request \
- rpc \
- server \
- srv_util \
- socket \
- thread \
- timer \
- transport \
- util
-
-include ${ROOT}/mk/lib.mk
-
diff --git a/libixp/README b/libixp/README
@@ -1,14 +0,0 @@
-libixp - simple 9P client-/server-library
-===============================
-libixp is an extremly simple, stand-alone 9P library.
-
-
-Installation
-------------
-Edit config.mk to match your local setup. libixp is installed into
-/usr/local by default.
-
-Afterwards enter the following command to build and install libixp
-(if necessary as root):
-
- $ make clean install
diff --git a/libixp/client.c b/libixp/client.c
@@ -1,676 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <assert.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-#define nelem(ary) (sizeof(ary) / sizeof(*ary))
-
-enum {
- RootFid = 1,
-};
-
-static int
-min(int a, int b) {
- if(a < b)
- return a;
- return b;
-}
-
-static IxpCFid*
-getfid(IxpClient *c) {
- IxpCFid *f;
-
- thread->lock(&c->lk);
- f = c->freefid;
- if(f != nil)
- c->freefid = f->next;
- else {
- f = emallocz(sizeof *f);
- f->client = c;
- f->fid = ++c->lastfid;
- thread->initmutex(&f->iolock);
- }
- f->next = nil;
- f->open = 0;
- thread->unlock(&c->lk);
- return f;
-}
-
-static void
-putfid(IxpCFid *f) {
- IxpClient *c;
-
- c = f->client;
- thread->lock(&c->lk);
- if(f->fid == c->lastfid) {
- c->lastfid--;
- thread->mdestroy(&f->iolock);
- free(f);
- }else {
- f->next = c->freefid;
- c->freefid = f;
- }
- thread->unlock(&c->lk);
-}
-
-static int
-dofcall(IxpClient *c, Fcall *fcall) {
- Fcall *ret;
-
- ret = muxrpc(c, fcall);
- if(ret == nil)
- return 0;
- if(ret->hdr.type == RError) {
- werrstr("%s", ret->error.ename);
- goto fail;
- }
- if(ret->hdr.type != (fcall->hdr.type^1)) {
- werrstr("received mismatched fcall");
- goto fail;
- }
- memcpy(fcall, ret, sizeof *fcall);
- free(ret);
- return 1;
-fail:
- ixp_freefcall(fcall);
- free(ret);
- return 0;
-}
-
-/**
- * Function: ixp_unmount
- *
- * Unmounts the client P<c> and frees its data structures.
- */
-void
-ixp_unmount(IxpClient *c) {
- IxpCFid *f;
-
- shutdown(c->fd, SHUT_RDWR);
- close(c->fd);
-
- muxfree(c);
-
- while((f = c->freefid)) {
- c->freefid = f->next;
- thread->mdestroy(&f->iolock);
- free(f);
- }
- free(c->rmsg.data);
- free(c->wmsg.data);
- free(c);
-}
-
-static void
-allocmsg(IxpClient *c, int n) {
- c->rmsg.size = n;
- c->wmsg.size = n;
- c->rmsg.data = erealloc(c->rmsg.data, n);
- c->wmsg.data = erealloc(c->wmsg.data, n);
-}
-
-/**
- * Function: ixp_mountfd
- * Function: ixp_mount
- * Function: ixp_nsmount
- *
- * Params:
- * fd - A file descriptor which is already connected
- * to a 9P server.
- * address - An address (in Plan 9 resource fomat) at
- * which to connect to a 9P server.
- * name - The name of a socket in the process's canonical
- * namespace directory.
- *
- * Initiate a 9P connection with the server at P<address>,
- * connected to on P<fd>, or under the process's namespace
- * directory as P<name>.
- *
- * Returns:
- * A pointer to a new 9P client.
- */
-
-IxpClient*
-ixp_mountfd(int fd) {
- IxpClient *c;
- Fcall fcall;
-
- c = emallocz(sizeof *c);
- c->fd = fd;
-
- muxinit(c);
-
- allocmsg(c, 256);
- c->lastfid = RootFid;
- /* Override tag matching on TVersion */
- c->mintag = IXP_NOTAG;
- c->maxtag = IXP_NOTAG+1;
-
- fcall.hdr.type = TVersion;
- fcall.version.msize = IXP_MAX_MSG;
- fcall.version.version = IXP_VERSION;
-
- if(dofcall(c, &fcall) == 0) {
- ixp_unmount(c);
- return nil;
- }
-
- if(strcmp(fcall.version.version, IXP_VERSION)
- || fcall.version.msize > IXP_MAX_MSG) {
- werrstr("bad 9P version response");
- ixp_unmount(c);
- return nil;
- }
-
- c->mintag = 0;
- c->maxtag = 255;
- c->msize = fcall.version.msize;
-
- allocmsg(c, fcall.version.msize);
- ixp_freefcall(&fcall);
-
- fcall.hdr.type = TAttach;
- fcall.hdr.fid = RootFid;
- fcall.tattach.afid = IXP_NOFID;
- fcall.tattach.uname = getenv("USER");
- fcall.tattach.aname = "";
- if(dofcall(c, &fcall) == 0) {
- ixp_unmount(c);
- return nil;
- }
-
- return c;
-}
-
-IxpClient*
-ixp_mount(const char *address) {
- int fd;
-
- fd = ixp_dial(address);
- if(fd < 0)
- return nil;
- return ixp_mountfd(fd);
-}
-
-IxpClient*
-ixp_nsmount(const char *name) {
- char *address;
- IxpClient *c;
-
- address = ixp_namespace();
- if(address)
- address = ixp_smprint("unix!%s/%s", address, name);
- if(address == nil)
- return nil;
- c = ixp_mount(address);
- free(address);
- return c;
-}
-
-static IxpCFid*
-walk(IxpClient *c, const char *path) {
- IxpCFid *f;
- char *p;
- Fcall fcall;
- int n;
-
- p = estrdup(path);
- n = tokenize(fcall.twalk.wname, nelem(fcall.twalk.wname), p, '/');
- f = getfid(c);
-
- fcall.hdr.type = TWalk;
- fcall.hdr.fid = RootFid;
- fcall.twalk.nwname = n;
- fcall.twalk.newfid = f->fid;
- if(dofcall(c, &fcall) == 0)
- goto fail;
- if(fcall.rwalk.nwqid < n) {
- werrstr("File does not exist");
- if(fcall.rwalk.nwqid == 0)
- werrstr("Protocol botch");
- goto fail;
- }
-
- f->qid = fcall.rwalk.wqid[n-1];
-
- ixp_freefcall(&fcall);
- free(p);
- return f;
-fail:
- putfid(f);
- free(p);
- return nil;
-}
-
-static IxpCFid*
-walkdir(IxpClient *c, char *path, const char **rest) {
- char *p;
-
- p = path + strlen(path) - 1;
- assert(p >= path);
- while(*p == '/')
- *p-- = '\0';
-
- while((p > path) && (*p != '/'))
- p--;
- if(*p != '/') {
- werrstr("bad path");
- return nil;
- }
-
- *p++ = '\0';
- *rest = p;
- return walk(c, path);
-}
-
-static int
-clunk(IxpCFid *f) {
- IxpClient *c;
- Fcall fcall;
- int ret;
-
- c = f->client;
-
- fcall.hdr.type = TClunk;
- fcall.hdr.fid = f->fid;
- ret = dofcall(c, &fcall);
- if(ret)
- putfid(f);
- ixp_freefcall(&fcall);
- return ret;
-}
-
-/**
- * Function: ixp_remove
- *
- * Params:
- * path - The path of the file to remove.
- *
- * Removes a file or directory from the remote server.
- *
- * Returns:
- * ixp_remove returns 0 on failure, 1 on success.
- */
-
-int
-ixp_remove(IxpClient *c, const char *path) {
- Fcall fcall;
- IxpCFid *f;
- int ret;
-
- if((f = walk(c, path)) == nil)
- return 0;
-
- fcall.hdr.type = TRemove;
- fcall.hdr.fid = f->fid;;
- ret = dofcall(c, &fcall);
- ixp_freefcall(&fcall);
- putfid(f);
-
- return ret;
-}
-
-static void
-initfid(IxpCFid *f, Fcall *fcall) {
- f->open = 1;
- f->offset = 0;
- f->iounit = fcall->ropen.iounit;
- if(f->iounit == 0 || fcall->ropen.iounit > f->client->msize-24)
- f->iounit = f->client->msize-24;
- f->qid = fcall->ropen.qid;
-}
-
-/**
- * Function: ixp_create
- * Function: ixp_open
- *
- * Params:
- * path - The path of the file to open or create.
- * perm - The permissions with which to create the new
- * file. These will be ANDed with those of the
- * parent directory by the server.
- * mode - The file's open mode.
- *
- * ixp_open and ixp_create each open a file at P<path>.
- * P<mode> must include OREAD, OWRITE, or ORDWR, and may
- * include any of the modes specified in 9pmodes(3).
- * ixp_create, additionally, creates a file at P<path> if it
- * doesn't already exist.
- *
- * Returns:
- * A pointer on which to operate on the newly
- * opened file.
- */
-
-IxpCFid*
-ixp_create(IxpClient *c, const char *path, uint perm, uchar mode) {
- Fcall fcall;
- IxpCFid *f;
- char *tpath;;
-
- tpath = estrdup(path);
-
- f = walkdir(c, tpath, &path);
- if(f == nil)
- goto done;
-
- fcall.hdr.type = TCreate;
- fcall.hdr.fid = f->fid;
- fcall.tcreate.name = (char*)(uintptr_t)path;
- fcall.tcreate.perm = perm;
- fcall.tcreate.mode = mode;
-
- if(dofcall(c, &fcall) == 0) {
- clunk(f);
- f = nil;
- goto done;
- }
-
- initfid(f, &fcall);
- f->mode = mode;
-
- ixp_freefcall(&fcall);
-
-done:
- free(tpath);
- return f;
-}
-
-IxpCFid*
-ixp_open(IxpClient *c, const char *path, uchar mode) {
- Fcall fcall;
- IxpCFid *f;
-
- f = walk(c, path);
- if(f == nil)
- return nil;
-
- fcall.hdr.type = TOpen;
- fcall.hdr.fid = f->fid;
- fcall.topen.mode = mode;
-
- if(dofcall(c, &fcall) == 0) {
- clunk(f);
- return nil;
- }
-
- initfid(f, &fcall);
- f->mode = mode;
-
- ixp_freefcall(&fcall);
- return f;
-}
-
-/**
- * Function: ixp_close
- *
- * Closes the file pointed to by P<f> and frees its
- * associated data structures;
- *
- * Returns:
- * Returns 1 on success, and zero on failure.
- */
-
-int
-ixp_close(IxpCFid *f) {
- return clunk(f);
-}
-
-static Stat*
-_stat(IxpClient *c, ulong fid) {
- IxpMsg msg;
- Fcall fcall;
- Stat *stat;
-
- fcall.hdr.type = TStat;
- fcall.hdr.fid = fid;
- if(dofcall(c, &fcall) == 0)
- return nil;
-
- msg = ixp_message((char*)fcall.rstat.stat, fcall.rstat.nstat, MsgUnpack);
-
- stat = emalloc(sizeof *stat);
- ixp_pstat(&msg, stat);
- ixp_freefcall(&fcall);
- if(msg.pos > msg.end) {
- free(stat);
- stat = nil;
- }
- return stat;
-}
-
-/**
- * Function: ixp_stat
- * Function: ixp_fstat
- *
- * Params:
- * path - The path of the file to stat.
- * f - A CFid of an open file to stat.
- *
- * Stats the file at P<path> or pointed to by P<f>.
- *
- * Returns:
- * Returns a Stat structure, which must be freed by
- * the caller with free(3).
- *
- * S<Stat>
- */
-
-Stat*
-ixp_stat(IxpClient *c, const char *path) {
- Stat *stat;
- IxpCFid *f;
-
- f = walk(c, path);
- if(f == nil)
- return nil;
-
- stat = _stat(c, f->fid);
- clunk(f);
- return stat;
-}
-
-Stat*
-ixp_fstat(IxpCFid *f) {
- return _stat(f->client, f->fid);
-}
-
-static long
-_pread(IxpCFid *f, char *buf, long count, vlong offset) {
- Fcall fcall;
- int n, len;
-
- len = 0;
- while(len < count) {
- n = min(count-len, f->iounit);
-
- fcall.hdr.type = TRead;
- fcall.hdr.fid = f->fid;
- fcall.tread.offset = offset;
- fcall.tread.count = n;
- if(dofcall(f->client, &fcall) == 0)
- return -1;
- if(fcall.rread.count > n)
- return -1;
-
- memcpy(buf+len, fcall.rread.data, fcall.rread.count);
- offset += fcall.rread.count;
- len += fcall.rread.count;
-
- ixp_freefcall(&fcall);
- if(fcall.rread.count < n)
- break;
- }
- return len;
-}
-
-/**
- * Function: ixp_read
- * Function: ixp_pread
- *
- * Params:
- * buf - A buffer in which to store the read data.
- * count - The number of bytes to read.
- * offset - The offset at which to begin reading.
- *
- * ixp_read and ixp_pread each read P<count> bytes of data
- * from the file pointed to by P<f>, into P<buf>. ixp_read
- * begins reading at its stored offset, and increments it by
- * the number of bytes read. ixp_pread reads beginning at
- * P<offset> and does not alter C<f>'s stored offset.
- *
- * Returns:
- * These functions return the number of bytes read on
- * success and -1 on failure.
- */
-
-long
-ixp_read(IxpCFid *f, void *buf, long count) {
- int n;
-
- thread->lock(&f->iolock);
- n = _pread(f, buf, count, f->offset);
- if(n > 0)
- f->offset += n;
- thread->unlock(&f->iolock);
- return n;
-}
-
-long
-ixp_pread(IxpCFid *f, void *buf, long count, vlong offset) {
- int n;
-
- thread->lock(&f->iolock);
- n = _pread(f, buf, count, offset);
- thread->unlock(&f->iolock);
- return n;
-}
-
-static long
-_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
- Fcall fcall;
- int n, len;
-
- len = 0;
- do {
- n = min(count-len, f->iounit);
- fcall.hdr.type = TWrite;
- fcall.hdr.fid = f->fid;
- fcall.twrite.offset = offset;
- fcall.twrite.data = (char*)buf + len;
- fcall.twrite.count = n;
- if(dofcall(f->client, &fcall) == 0)
- return -1;
-
- offset += fcall.rwrite.count;
- len += fcall.rwrite.count;
-
- ixp_freefcall(&fcall);
- if(fcall.rwrite.count < n)
- break;
- } while(len < count);
- return len;
-}
-
-/**
- * Function: ixp_write
- * Function: ixp_pwrite
- *
- * Params:
- * buf - A buffer holding the contents to store.
- * count - The number of bytes to store.
- * offset - The offset at which to write the data.
- *
- * ixp_write and ixp_pwrite each write P<count> bytes of
- * data stored in P<buf> to the file pointed to by C<f>.
- * ixp_write writes its data at its stored offset, and
- * increments it by P<count>. ixp_pwrite writes its data a
- * P<offset> and does not alter C<f>'s stored offset.
- *
- * Returns:
- * These functions return the number of bytes actually
- * written. Any value less than P<count> must be considered
- * a failure.
- */
-
-long
-ixp_write(IxpCFid *f, const void *buf, long count) {
- int n;
-
- thread->lock(&f->iolock);
- n = _pwrite(f, buf, count, f->offset);
- if(n > 0)
- f->offset += n;
- thread->unlock(&f->iolock);
- return n;
-}
-
-long
-ixp_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
- int n;
-
- thread->lock(&f->iolock);
- n = _pwrite(f, buf, count, offset);
- thread->unlock(&f->iolock);
- return n;
-}
-
-/**
- * Function: ixp_vprint
- * Function: ixp_print
- * Variable: ixp_vsmprint
- *
- * Params:
- * fmt - The string with which to format the data.
- * ap - A va_list holding the arguments to the format
- * string.
- * ... - The arguments to the format string.
- *
- * These functions act like the standard formatted IO
- * functions. They write the result of the formatting to the
- * file pointed to by C<f>.
- *
- * V<ixp_vsmprint> may be set to a function which will
- * format its arguments and return a null terminated string
- * allocated with malloc(3).
- *
- * Returns:
- * These functions return the number of bytes written.
- * There is currently no way to detect failure.
- */
-
-int
-ixp_vprint(IxpCFid *f, const char *fmt, va_list ap) {
- char *buf;
- int n;
-
- buf = ixp_vsmprint(fmt, ap);
- if(buf == nil)
- return -1;
-
- n = ixp_write(f, buf, strlen(buf));
- free(buf);
- return n;
-}
-
-int
-ixp_print(IxpCFid *f, const char *fmt, ...) {
- va_list ap;
- int n;
-
- va_start(ap, fmt);
- n = ixp_vprint(f, fmt, ap);
- va_end(ap);
-
- return n;
-}
-
diff --git a/libixp/convert.c b/libixp/convert.c
@@ -1,200 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "ixp_local.h"
-
-enum {
- SByte = 1,
- SWord = 2,
- SDWord = 4,
- SQWord = 8,
-};
-
-static void
-ixp_puint(IxpMsg *msg, uint size, ulong *val) {
- uchar *pos;
- int v;
-
- if(msg->pos + size <= msg->end) {
- pos = (uchar*)msg->pos;
- switch(msg->mode) {
- case MsgPack:
- v = *val;
- switch(size) {
- case SDWord:
- pos[3] = v>>24;
- pos[2] = v>>16;
- case SWord:
- pos[1] = v>>8;
- case SByte:
- pos[0] = v;
- break;
- }
- case MsgUnpack:
- v = 0;
- switch(size) {
- case SDWord:
- v |= pos[3]<<24;
- v |= pos[2]<<16;
- case SWord:
- v |= pos[1]<<8;
- case SByte:
- v |= pos[0];
- break;
- }
- *val = v;
- }
- }
- msg->pos += size;
-}
-
-void
-ixp_pu32(IxpMsg *msg, ulong *val) {
- ixp_puint(msg, SDWord, val);
-}
-void
-ixp_pu8(IxpMsg *msg, uchar *val) {
- ulong v;
-
- v = *val;
- ixp_puint(msg, SByte, &v);
- *val = (uchar)v;
-}
-void
-ixp_pu16(IxpMsg *msg, ushort *val) {
- ulong v;
-
- v = *val;
- ixp_puint(msg, SWord, &v);
- *val = (ushort)v;
-}
-void
-ixp_pu64(IxpMsg *msg, uvlong *val) {
- ulong vl, vb;
-
- vl = (uint)*val;
- vb = (uint)(*val>>32);
- ixp_puint(msg, SDWord, &vl);
- ixp_puint(msg, SDWord, &vb);
- *val = vl | ((uvlong)vb<<32);
-}
-
-void
-ixp_pstring(IxpMsg *msg, char **s) {
- ushort len;
-
- if(msg->mode == MsgPack)
- len = strlen(*s);
- ixp_pu16(msg, &len);
-
- if(msg->pos + len <= msg->end) {
- if(msg->mode == MsgUnpack) {
- *s = emalloc(len + 1);
- memcpy(*s, msg->pos, len);
- (*s)[len] = '\0';
- }else
- memcpy(msg->pos, *s, len);
- }
- msg->pos += len;
-}
-
-void
-ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
- char *s;
- uint i, size;
- ushort len;
-
- ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
- msg->pos = msg->end+1;
- return;
- }
-
- SET(s);
- if(msg->mode == MsgUnpack) {
- s = msg->pos;
- size = 0;
- for(i=0; i < *num; i++) {
- ixp_pu16(msg, &len);
- msg->pos += len;
- size += len;
- if(msg->pos > msg->end)
- return;
- }
- msg->pos = s;
- size += *num;
- s = emalloc(size);
- }
-
- for(i=0; i < *num; i++) {
- if(msg->mode == MsgPack)
- len = strlen(strings[i]);
- ixp_pu16(msg, &len);
-
- if(msg->mode == MsgUnpack) {
- memcpy(s, msg->pos, len);
- strings[i] = (char*)s;
- s += len;
- msg->pos += len;
- *s++ = '\0';
- }else
- ixp_pdata(msg, &strings[i], len);
- }
-}
-
-void
-ixp_pdata(IxpMsg *msg, char **data, uint len) {
- if(msg->pos + len <= msg->end) {
- if(msg->mode == MsgUnpack) {
- *data = emalloc(len);
- memcpy(*data, msg->pos, len);
- }else
- memcpy(msg->pos, *data, len);
- }
- msg->pos += len;
-}
-
-void
-ixp_pqid(IxpMsg *msg, Qid *qid) {
- ixp_pu8(msg, &qid->type);
- ixp_pu32(msg, &qid->version);
- ixp_pu64(msg, &qid->path);
-}
-
-void
-ixp_pqids(IxpMsg *msg, ushort *num, Qid qid[]) {
- int i;
-
- ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
- msg->pos = msg->end+1;
- return;
- }
-
- for(i = 0; i < *num; i++)
- ixp_pqid(msg, &qid[i]);
-}
-
-void
-ixp_pstat(IxpMsg *msg, Stat *stat) {
- ushort size;
-
- if(msg->mode == MsgPack)
- size = ixp_sizeof_stat(stat) - 2;
-
- ixp_pu16(msg, &size);
- ixp_pu16(msg, &stat->type);
- ixp_pu32(msg, &stat->dev);
- ixp_pqid(msg, &stat->qid);
- ixp_pu32(msg, &stat->mode);
- ixp_pu32(msg, &stat->atime);
- ixp_pu32(msg, &stat->mtime);
- ixp_pu64(msg, &stat->length);
- ixp_pstring(msg, &stat->name);
- ixp_pstring(msg, &stat->uid);
- ixp_pstring(msg, &stat->gid);
- ixp_pstring(msg, &stat->muid);
-}
diff --git a/libixp/error.c b/libixp/error.c
@@ -1,103 +0,0 @@
-/* Public Domain --Kris Maglione */
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "ixp_local.h"
-
-static int
-_vsnprint(char *buf, int n, const char *fmt, va_list ap) {
- return vsnprintf(buf, n, fmt, ap);
-}
-
-static char*
-_vsmprint(const char *fmt, va_list ap) {
- va_list al;
- char *buf = "";
- int n;
-
- va_copy(al, ap);
- n = vsnprintf(buf, 0, fmt, al);
- va_end(al);
-
- buf = malloc(++n);
- if(buf)
- vsnprintf(buf, n, fmt, ap);
- return buf;
-}
-
-int (*ixp_vsnprint)(char*, int, const char*, va_list) = _vsnprint;
-char* (*ixp_vsmprint)(const char*, va_list) = _vsmprint;
-
-/* Approach to errno handling taken from Plan 9 Port. */
-enum {
- EPLAN9 = 0x19283745,
-};
-
-/**
- * Function: ixp_errbuf
- * Function: ixp_errstr
- * Function: ixp_rerrstr
- * Function: ixp_werrstr
- *
- * Params:
- * buf - The buffer to read and/or fill.
- * n - The size of the buffer.
- * fmt - A format string with which to write the * errstr.
- * ... - Arguments to P<fmt>.
- *
- * These functions simulate Plan 9's errstr functionality.
- * They replace errno in libixp. Note that these functions
- * are not internationalized.
- *
- * F<ixp_errbuf> returns the errstr buffer for the current
- * thread. F<ixp_rerrstr> fills P<buf> with the data from
- * the current thread's error buffer, while F<ixp_errstr>
- * exchanges P<buf>'s contents with those of the current
- * thread's error buffer. F<ixp_werrstr> is takes a format
- * string from which to construct an errstr.
- *
- * Returns:
- * F<ixp_errbuf> returns the current thread's error
- * string buffer.
- */
-char*
-ixp_errbuf() {
- char *errbuf;
-
- errbuf = thread->errbuf();
- if(errno == EINTR)
- strncpy(errbuf, "interrupted", IXP_ERRMAX);
- else if(errno != EPLAN9)
- strncpy(errbuf, strerror(errno), IXP_ERRMAX);
- return errbuf;
-}
-
-void
-errstr(char *buf, int n) {
- char tmp[IXP_ERRMAX];
-
- strncpy(tmp, buf, sizeof tmp);
- rerrstr(buf, n);
- strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
- errno = EPLAN9;
-}
-
-void
-rerrstr(char *buf, int n) {
- strncpy(buf, ixp_errbuf(), n);
-}
-
-void
-werrstr(const char *fmt, ...) {
- char tmp[IXP_ERRMAX];
- va_list ap;
-
- va_start(ap, fmt);
- ixp_vsnprint(tmp, sizeof tmp, fmt, ap);
- va_end(ap);
- strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
- errno = EPLAN9;
-}
-
diff --git a/libixp/map.c b/libixp/map.c
@@ -1,132 +0,0 @@
-/* Written by Kris Maglione */
-/* Public domain */
-#include <stdlib.h>
-#include "ixp_local.h"
-
-/* Edit s/^([a-zA-Z].*)\n([a-z].*) {/\1 \2;/g x/^([^a-zA-Z]|static|$)/-+d s/ (\*map|val|*str)//g */
-
-struct MapEnt {
- ulong hash;
- const char* key;
- void* val;
- MapEnt* next;
-};
-
-MapEnt *NM;
-
-static void
-insert(MapEnt **e, ulong val, const char *key) {
- MapEnt *te;
-
- te = emallocz(sizeof *te);
- te->hash = val;
- te->key = key;
- te->next = *e;
- *e = te;
-}
-
-static MapEnt**
-map_getp(Map *map, ulong val, bool create, bool *exists) {
- MapEnt **e;
-
- e = &map->bucket[val%map->nhash];
- for(; *e; e = &(*e)->next)
- if((*e)->hash >= val) break;
- if(exists)
- *exists = *e && (*e)->hash == val;
-
- if(*e == nil || (*e)->hash != val) {
- if(create)
- insert(e, val, nil);
- else
- e = &NM;
- }
- return e;
-}
-
-void
-ixp_mapfree(Map *map, void (*destroy)(void*)) {
- int i;
- MapEnt *e;
-
- thread->wlock(&map->lock);
- for(i=0; i < map->nhash; i++)
- while((e = map->bucket[i])) {
- map->bucket[i] = e->next;
- if(destroy)
- destroy(e->val);
- free(e);
- }
- thread->wunlock(&map->lock);
- thread->rwdestroy(&map->lock);
-}
-
-void
-ixp_mapexec(Map *map, void (*run)(void*, void*), void *context) {
- int i;
- MapEnt *e;
-
- thread->rlock(&map->lock);
- for(i=0; i < map->nhash; i++)
- for(e=map->bucket[i]; e; e=e->next)
- run(context, e->val);
- thread->runlock(&map->lock);
-}
-
-void
-ixp_mapinit(Map *map, MapEnt **buckets, int nbuckets) {
-
- map->bucket = buckets;
- map->nhash = nbuckets;
-
- thread->initrwlock(&map->lock);
-}
-
-bool
-ixp_mapinsert(Map *map, ulong key, void *val, bool overwrite) {
- MapEnt *e;
- bool existed, res;
-
- res = true;
- thread->wlock(&map->lock);
- e = *map_getp(map, key, true, &existed);
- if(existed && !overwrite)
- res = false;
- else
- e->val = val;
- thread->wunlock(&map->lock);
- return res;
-}
-
-void*
-ixp_mapget(Map *map, ulong val) {
- MapEnt *e;
- void *res;
-
- thread->rlock(&map->lock);
- e = *map_getp(map, val, false, nil);
- res = e ? e->val : nil;
- thread->runlock(&map->lock);
- return res;
-}
-
-void*
-ixp_maprm(Map *map, ulong val) {
- MapEnt **e, *te;
- void *ret;
-
- ret = nil;
- thread->wlock(&map->lock);
- e = map_getp(map, val, false, nil);
- if(*e) {
- te = *e;
- ret = te->val;
- *e = te->next;
- thread->wunlock(&map->lock);
- free(te);
- }
- else
- thread->wunlock(&map->lock);
- return ret;
-}
-
diff --git a/libixp/message.c b/libixp/message.c
@@ -1,205 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "ixp_local.h"
-
-enum {
- SByte = 1,
- SWord = 2,
- SDWord = 4,
- SQWord = 8,
-};
-
-#define SString(s) (SWord + strlen(s))
-enum {
- SQid = SByte + SDWord + SQWord,
-};
-
-IxpMsg
-ixp_message(char *data, uint length, uint mode) {
- IxpMsg m;
-
- m.data = data;
- m.pos = data;
- m.end = data + length;
- m.size = length;
- m.mode = mode;
- return m;
-}
-
-void
-ixp_freestat(Stat *s) {
- free(s->name);
- free(s->uid);
- free(s->gid);
- free(s->muid);
- s->name = s->uid = s->gid = s->muid = nil;
-}
-
-void
-ixp_freefcall(Fcall *fcall) {
- switch(fcall->hdr.type) {
- case RStat:
- free(fcall->rstat.stat);
- fcall->rstat.stat = nil;
- break;
- case RRead:
- free(fcall->rread.data);
- fcall->rread.data = nil;
- break;
- case RVersion:
- free(fcall->version.version);
- fcall->version.version = nil;
- break;
- case RError:
- free(fcall->error.ename);
- fcall->error.ename = nil;
- break;
- }
-}
-
-ushort
-ixp_sizeof_stat(Stat * stat) {
- return SWord /* size */
- + SWord /* type */
- + SDWord /* dev */
- + SQid /* qid */
- + 3 * SDWord /* mode, atime, mtime */
- + SQWord /* length */
- + SString(stat->name)
- + SString(stat->uid)
- + SString(stat->gid)
- + SString(stat->muid);
-}
-
-void
-ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
- ixp_pu8(msg, &fcall->hdr.type);
- ixp_pu16(msg, &fcall->hdr.tag);
-
- switch (fcall->hdr.type) {
- case TVersion:
- case RVersion:
- ixp_pu32(msg, &fcall->version.msize);
- ixp_pstring(msg, &fcall->version.version);
- break;
- case TAuth:
- ixp_pu32(msg, &fcall->tauth.afid);
- ixp_pstring(msg, &fcall->tauth.uname);
- ixp_pstring(msg, &fcall->tauth.aname);
- break;
- case RAuth:
- ixp_pqid(msg, &fcall->rauth.aqid);
- break;
- case RAttach:
- ixp_pqid(msg, &fcall->rattach.qid);
- break;
- case TAttach:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu32(msg, &fcall->tattach.afid);
- ixp_pstring(msg, &fcall->tattach.uname);
- ixp_pstring(msg, &fcall->tattach.aname);
- break;
- case RError:
- ixp_pstring(msg, &fcall->error.ename);
- break;
- case TFlush:
- ixp_pu16(msg, &fcall->tflush.oldtag);
- break;
- case TWalk:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu32(msg, &fcall->twalk.newfid);
- ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname);
- break;
- case RWalk:
- ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
- break;
- case TOpen:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu8(msg, &fcall->topen.mode);
- break;
- case ROpen:
- case RCreate:
- ixp_pqid(msg, &fcall->ropen.qid);
- ixp_pu32(msg, &fcall->ropen.iounit);
- break;
- case TCreate:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pstring(msg, &fcall->tcreate.name);
- ixp_pu32(msg, &fcall->tcreate.perm);
- ixp_pu8(msg, &fcall->tcreate.mode);
- break;
- case TRead:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu64(msg, &fcall->tread.offset);
- ixp_pu32(msg, &fcall->tread.count);
- break;
- case RRead:
- ixp_pu32(msg, &fcall->rread.count);
- ixp_pdata(msg, &fcall->rread.data, fcall->rread.count);
- break;
- case TWrite:
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu64(msg, &fcall->twrite.offset);
- ixp_pu32(msg, &fcall->twrite.count);
- ixp_pdata(msg, &fcall->twrite.data, fcall->twrite.count);
- break;
- case RWrite:
- ixp_pu32(msg, &fcall->rwrite.count);
- break;
- case TClunk:
- case TRemove:
- case TStat:
- ixp_pu32(msg, &fcall->hdr.fid);
- break;
- case RStat:
- ixp_pu16(msg, &fcall->rstat.nstat);
- ixp_pdata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat);
- break;
- case TWStat: {
- ushort size;
- ixp_pu32(msg, &fcall->hdr.fid);
- ixp_pu16(msg, &size);
- ixp_pstat(msg, &fcall->twstat.stat);
- break;
- }
- }
-}
-
-uint
-ixp_fcall2msg(IxpMsg *msg, Fcall *fcall) {
- ulong size;
-
- msg->end = msg->data + msg->size;
- msg->pos = msg->data + SDWord;
- msg->mode = MsgPack;
- ixp_pfcall(msg, fcall);
-
- if(msg->pos > msg->end)
- return 0;
-
- msg->end = msg->pos;
- size = msg->end - msg->data;
-
- msg->pos = msg->data;
- ixp_pu32(msg, &size);
-
- msg->pos = msg->data;
- return size;
-}
-
-uint
-ixp_msg2fcall(IxpMsg *msg, Fcall *fcall) {
- msg->pos = msg->data + SDWord;
- msg->mode = MsgUnpack;
- ixp_pfcall(msg, fcall);
-
- if(msg->pos > msg->end)
- return 0;
-
- return msg->pos - msg->data;
-}
-
diff --git a/libixp/request.c b/libixp/request.c
@@ -1,550 +0,0 @@
-/* Copyright ©2006-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
-#include "ixp_local.h"
-
-static void handlereq(Ixp9Req *r);
-
-static void
-_printfcall(Fcall *f) {
- USED(f);
-}
-void (*ixp_printfcall)(Fcall*) = _printfcall;
-
-static int
-min(int a, int b) {
- if(a < b)
- return a;
- return b;
-}
-
-static char
- Eduptag[] = "tag in use",
- Edupfid[] = "fid in use",
- Enofunc[] = "function not implemented",
- Eopen[] = "fid is already open",
- Enofile[] = "file does not exist",
- Enoread[] = "file not open for reading",
- Enofid[] = "fid does not exist",
- Enotag[] = "tag does not exist",
- Enotdir[] = "not a directory",
- Eintr[] = "interrupted",
- Eisdir[] = "cannot perform operation on a directory";
-
-enum {
- TAG_BUCKETS = 61,
- FID_BUCKETS = 61,
-};
-
-struct Ixp9Conn {
- Map tagmap;
- Map fidmap;
- MapEnt* taghash[TAG_BUCKETS];
- MapEnt* fidhash[FID_BUCKETS];
- Ixp9Srv* srv;
- IxpConn* conn;
- IxpMutex rlock;
- IxpMutex wlock;
- IxpMsg rmsg;
- IxpMsg wmsg;
- int ref;
-};
-
-static void
-decref_p9conn(Ixp9Conn *p9conn) {
- thread->lock(&p9conn->wlock);
- if(--p9conn->ref > 0) {
- thread->unlock(&p9conn->wlock);
- return;
- }
- thread->unlock(&p9conn->wlock);
-
- assert(p9conn->conn == nil);
-
- thread->mdestroy(&p9conn->rlock);
- thread->mdestroy(&p9conn->wlock);
-
- ixp_mapfree(&p9conn->tagmap, nil);
- ixp_mapfree(&p9conn->fidmap, nil);
-
- free(p9conn->rmsg.data);
- free(p9conn->wmsg.data);
- free(p9conn);
-}
-
-static void*
-createfid(Map *map, int fid, Ixp9Conn *p9conn) {
- Fid *f;
-
- f = emallocz(sizeof *f);
- p9conn->ref++;
- f->conn = p9conn;
- f->fid = fid;
- f->omode = -1;
- f->map = map;
- if(ixp_mapinsert(map, fid, f, false))
- return f;
- free(f);
- return nil;
-}
-
-static int
-destroyfid(Ixp9Conn *p9conn, ulong fid) {
- Fid *f;
-
- f = ixp_maprm(&p9conn->fidmap, fid);
- if(f == nil)
- return 0;
-
- if(p9conn->srv->freefid)
- p9conn->srv->freefid(f);
-
- decref_p9conn(p9conn);
- free(f);
- return 1;
-}
-
-static void
-handlefcall(IxpConn *c) {
- Fcall fcall = {0};
- Ixp9Conn *p9conn;
- Ixp9Req *req;
-
- p9conn = c->aux;
-
- thread->lock(&p9conn->rlock);
- if(ixp_recvmsg(c->fd, &p9conn->rmsg) == 0)
- goto Fail;
- if(ixp_msg2fcall(&p9conn->rmsg, &fcall) == 0)
- goto Fail;
- thread->unlock(&p9conn->rlock);
-
- req = emallocz(sizeof *req);
- p9conn->ref++;
- req->conn = p9conn;
- req->srv = p9conn->srv;
- req->ifcall = fcall;
- p9conn->conn = c;
-
- if(!ixp_mapinsert(&p9conn->tagmap, fcall.hdr.tag, req, false)) {
- respond(req, Eduptag);
- return;
- }
-
- handlereq(req);
- return;
-
-Fail:
- thread->unlock(&p9conn->rlock);
- ixp_hangup(c);
- return;
-}
-
-static void
-handlereq(Ixp9Req *r) {
- Ixp9Conn *p9conn;
- Ixp9Srv *srv;
-
- p9conn = r->conn;
- srv = p9conn->srv;
-
- ixp_printfcall(&r->ifcall);
-
- switch(r->ifcall.hdr.type) {
- default:
- respond(r, Enofunc);
- break;
- case TVersion:
- if(!strcmp(r->ifcall.version.version, "9P"))
- r->ofcall.version.version = "9P";
- else if(!strcmp(r->ifcall.version.version, "9P2000"))
- r->ofcall.version.version = "9P2000";
- else
- r->ofcall.version.version = "unknown";
- r->ofcall.version.msize = r->ifcall.version.msize;
- respond(r, nil);
- break;
- case TAttach:
- if(!(r->fid = createfid(&p9conn->fidmap, r->ifcall.hdr.fid, p9conn))) {
- respond(r, Edupfid);
- return;
- }
- /* attach is a required function */
- srv->attach(r);
- break;
- case TClunk:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(!srv->clunk) {
- respond(r, nil);
- return;
- }
- srv->clunk(r);
- break;
- case TFlush:
- if(!(r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag))) {
- respond(r, Enotag);
- return;
- }
- if(!srv->flush) {
- respond(r, Enofunc);
- return;
- }
- srv->flush(r);
- break;
- case TCreate:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(r->fid->omode != -1) {
- respond(r, Eopen);
- return;
- }
- if(!(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
- return;
- }
- if(!p9conn->srv->create) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->create(r);
- break;
- case TOpen:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if((r->fid->qid.type&QTDIR) && (r->ifcall.topen.mode|P9_ORCLOSE) != (P9_OREAD|P9_ORCLOSE)) {
- respond(r, Eisdir);
- return;
- }
- r->ofcall.ropen.qid = r->fid->qid;
- if(!p9conn->srv->open) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->open(r);
- break;
- case TRead:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(r->fid->omode == -1 || r->fid->omode == P9_OWRITE) {
- respond(r, Enoread);
- return;
- }
- if(!p9conn->srv->read) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->read(r);
- break;
- case TRemove:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(!p9conn->srv->remove) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->remove(r);
- break;
- case TStat:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(!p9conn->srv->stat) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->stat(r);
- break;
- case TWalk:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if(r->fid->omode != -1) {
- respond(r, "cannot walk from an open fid");
- return;
- }
- if(r->ifcall.twalk.nwname && !(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
- return;
- }
- if((r->ifcall.hdr.fid != r->ifcall.twalk.newfid)) {
- if(!(r->newfid = createfid(&p9conn->fidmap, r->ifcall.twalk.newfid, p9conn))) {
- respond(r, Edupfid);
- return;
- }
- }else
- r->newfid = r->fid;
- if(!p9conn->srv->walk) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->walk(r);
- break;
- case TWrite:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if((r->fid->omode&3) != P9_OWRITE && (r->fid->omode&3) != P9_ORDWR) {
- respond(r, "write on fid not opened for writing");
- return;
- }
- if(!p9conn->srv->write) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->write(r);
- break;
- case TWStat:
- if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
- return;
- }
- if((ushort)~r->ifcall.twstat.stat.type) {
- respond(r, "wstat of type");
- return;
- }
- if((uint)~r->ifcall.twstat.stat.dev) {
- respond(r, "wstat of dev");
- return;
- }
- if((uchar)~r->ifcall.twstat.stat.qid.type || (ulong)~r->ifcall.twstat.stat.qid.version || (uvlong)~r->ifcall.twstat.stat.qid.path) {
- respond(r, "wstat of qid");
- return;
- }
- if(r->ifcall.twstat.stat.muid && r->ifcall.twstat.stat.muid[0]) {
- respond(r, "wstat of muid");
- return;
- }
- if((ulong)~r->ifcall.twstat.stat.mode && ((r->ifcall.twstat.stat.mode&DMDIR)>>24) != r->fid->qid.type&QTDIR) {
- respond(r, "wstat on DMDIR bit");
- return;
- }
- if(!p9conn->srv->wstat) {
- respond(r, Enofunc);
- return;
- }
- p9conn->srv->wstat(r);
- break;
- /* Still to be implemented: auth */
- }
-}
-
-void
-respond(Ixp9Req *r, const char *error) {
- Ixp9Conn *p9conn;
- int msize;
-
- p9conn = r->conn;
-
- switch(r->ifcall.hdr.type) {
- default:
- if(!error)
- assert(!"Respond called on unsupported fcall type");
- break;
- case TVersion:
- assert(error == nil);
- free(r->ifcall.version.version);
-
- thread->lock(&p9conn->rlock);
- thread->lock(&p9conn->wlock);
- msize = min(r->ofcall.version.msize, IXP_MAX_MSG);
- p9conn->rmsg.data = erealloc(p9conn->rmsg.data, msize);
- p9conn->wmsg.data = erealloc(p9conn->wmsg.data, msize);
- p9conn->rmsg.size = msize;
- p9conn->wmsg.size = msize;
- thread->unlock(&p9conn->wlock);
- thread->unlock(&p9conn->rlock);
- r->ofcall.version.msize = msize;
- break;
- case TAttach:
- if(error)
- destroyfid(p9conn, r->fid->fid);
- free(r->ifcall.tattach.uname);
- free(r->ifcall.tattach.aname);
- break;
- case TOpen:
- case TCreate:
- if(!error) {
- r->ofcall.ropen.iounit = p9conn->rmsg.size - 24;
- r->fid->iounit = r->ofcall.ropen.iounit;
- r->fid->omode = r->ifcall.topen.mode;
- r->fid->qid = r->ofcall.ropen.qid;
- }
- free(r->ifcall.tcreate.name);
- break;
- case TWalk:
- if(error || r->ofcall.rwalk.nwqid < r->ifcall.twalk.nwname) {
- if(r->ifcall.hdr.fid != r->ifcall.twalk.newfid && r->newfid)
- destroyfid(p9conn, r->newfid->fid);
- if(!error && r->ofcall.rwalk.nwqid == 0)
- error = Enofile;
- }else{
- if(r->ofcall.rwalk.nwqid == 0)
- r->newfid->qid = r->fid->qid;
- else
- r->newfid->qid = r->ofcall.rwalk.wqid[r->ofcall.rwalk.nwqid-1];
- }
- free(*r->ifcall.twalk.wname);
- break;
- case TWrite:
- free(r->ifcall.twrite.data);
- break;
- case TRemove:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
- break;
- case TClunk:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
- break;
- case TFlush:
- if((r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag)))
- respond(r->oldreq, Eintr);
- break;
- case TWStat:
- ixp_freestat(&r->ifcall.twstat.stat);
- break;
- case TRead:
- case TStat:
- break;
- /* Still to be implemented: auth */
- }
-
- r->ofcall.hdr.tag = r->ifcall.hdr.tag;
-
- if(error == nil)
- r->ofcall.hdr.type = r->ifcall.hdr.type + 1;
- else {
- r->ofcall.hdr.type = RError;
- r->ofcall.error.ename = (char*)error;
- }
-
- ixp_printfcall(&r->ofcall);
-
- ixp_maprm(&p9conn->tagmap, r->ifcall.hdr.tag);;
-
- if(p9conn->conn) {
- thread->lock(&p9conn->wlock);
- msize = ixp_fcall2msg(&p9conn->wmsg, &r->ofcall);
- if(ixp_sendmsg(p9conn->conn->fd, &p9conn->wmsg) != msize)
- ixp_hangup(p9conn->conn);
- thread->unlock(&p9conn->wlock);
- }
-
- switch(r->ofcall.hdr.type) {
- case RStat:
- free(r->ofcall.rstat.stat);
- break;
- case RRead:
- free(r->ofcall.rread.data);
- break;
- }
- free(r);
- decref_p9conn(p9conn);
-}
-
-/* Flush a pending request */
-static void
-voidrequest(void *context, void *arg) {
- Ixp9Req *orig_req, *flush_req;
- Ixp9Conn *conn;
-
- orig_req = arg;
- conn = orig_req->conn;
- conn->ref++;
-
- flush_req = emallocz(sizeof *orig_req);
- flush_req->ifcall.hdr.type = TFlush;
- flush_req->ifcall.hdr.tag = IXP_NOTAG;
- flush_req->ifcall.tflush.oldtag = orig_req->ifcall.hdr.tag;
- flush_req->conn = conn;
-
- flush_req->aux = *(void**)context;
- *(void**)context = flush_req;
-}
-
-/* Clunk an open Fid */
-static void
-voidfid(void *context, void *arg) {
- Ixp9Conn *p9conn;
- Ixp9Req *clunk_req;
- Fid *fid;
-
- fid = arg;
- p9conn = fid->conn;
- p9conn->ref++;
-
- clunk_req = emallocz(sizeof *clunk_req);
- clunk_req->ifcall.hdr.type = TClunk;
- clunk_req->ifcall.hdr.tag = IXP_NOTAG;
- clunk_req->ifcall.hdr.fid = fid->fid;
- clunk_req->fid = fid;
- clunk_req->conn = p9conn;
-
- clunk_req->aux = *(void**)context;
- *(void**)context = clunk_req;
-}
-
-static void
-cleanupconn(IxpConn *c) {
- Ixp9Conn *p9conn;
- Ixp9Req *req, *r;
-
- p9conn = c->aux;
- p9conn->conn = nil;
- req = nil;
- if(p9conn->ref > 1) {
- ixp_mapexec(&p9conn->fidmap, voidfid, &req);
- ixp_mapexec(&p9conn->tagmap, voidrequest, &req);
- }
- while((r = req)) {
- req = r->aux;
- r->aux = nil;
- handlereq(r);
- }
- decref_p9conn(p9conn);
-}
-
-/* Handle incoming 9P connections */
-void
-serve_9pcon(IxpConn *c) {
- Ixp9Conn *p9conn;
- int fd;
-
- fd = accept(c->fd, nil, nil);
- if(fd < 0)
- return;
-
- p9conn = emallocz(sizeof *p9conn);
- p9conn->ref++;
- p9conn->srv = c->aux;
- p9conn->rmsg.size = 1024;
- p9conn->wmsg.size = 1024;
- p9conn->rmsg.data = emalloc(p9conn->rmsg.size);
- p9conn->wmsg.data = emalloc(p9conn->wmsg.size);
-
- ixp_mapinit(&p9conn->tagmap, p9conn->taghash, nelem(p9conn->taghash));
- ixp_mapinit(&p9conn->fidmap, p9conn->fidhash, nelem(p9conn->fidhash));
- thread->initmutex(&p9conn->rlock);
- thread->initmutex(&p9conn->wlock);
-
- ixp_listen(c->srv, fd, p9conn, handlefcall, cleanupconn);
-}
diff --git a/libixp/rpc.c b/libixp/rpc.c
@@ -1,262 +0,0 @@
-/* From Plan 9's libmux.
- * Copyright (c) 2003 Russ Cox, Massachusetts Institute of Technology
- * Distributed under the same terms as libixp.
- */
-#include <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "ixp_local.h"
-
-static int gettag(IxpClient*, IxpRpc*);
-static void puttag(IxpClient*, IxpRpc*);
-static void enqueue(IxpClient*, IxpRpc*);
-static void dequeue(IxpClient*, IxpRpc*);
-
-void
-muxinit(IxpClient *mux)
-{
- mux->tagrend.mutex = &mux->lk;
- mux->sleep.next = &mux->sleep;
- mux->sleep.prev = &mux->sleep;
- thread->initmutex(&mux->lk);
- thread->initmutex(&mux->rlock);
- thread->initmutex(&mux->wlock);
- thread->initrendez(&mux->tagrend);
-}
-
-void
-muxfree(IxpClient *mux)
-{
- thread->mdestroy(&mux->lk);
- thread->mdestroy(&mux->rlock);
- thread->mdestroy(&mux->wlock);
- thread->rdestroy(&mux->tagrend);
- free(mux->wait);
-}
-
-static void
-initrpc(IxpClient *mux, IxpRpc *r)
-{
- r->mux = mux;
- r->waiting = 1;
- r->r.mutex = &mux->lk;
- r->p = nil;
- thread->initrendez(&r->r);
-}
-
-static void
-freemuxrpc(IxpRpc *r)
-{
- thread->rdestroy(&r->r);
-}
-
-static int
-sendrpc(IxpRpc *r, Fcall *f)
-{
- int ret;
- IxpClient *mux;
-
- ret = 0;
- mux = r->mux;
- /* assign the tag, add selves to response queue */
- thread->lock(&mux->lk);
- r->tag = gettag(mux, r);
- f->hdr.tag = r->tag;
- enqueue(mux, r);
- thread->unlock(&mux->lk);
-
- thread->lock(&mux->wlock);
- if(!ixp_fcall2msg(&mux->wmsg, f) || !ixp_sendmsg(mux->fd, &mux->wmsg)) {
- /* werrstr("settag/send tag %d: %r", tag); fprint(2, "%r\n"); */
- thread->lock(&mux->lk);
- dequeue(mux, r);
- puttag(mux, r);
- thread->unlock(&mux->lk);
- ret = -1;
- }
- thread->unlock(&mux->wlock);
- return ret;
-}
-
-static Fcall*
-muxrecv(IxpClient *mux)
-{
- Fcall *f;
-
- f = nil;
- thread->lock(&mux->rlock);
- if(ixp_recvmsg(mux->fd, &mux->rmsg) == 0)
- goto fail;
- f = emallocz(sizeof *f);
- if(ixp_msg2fcall(&mux->rmsg, f) == 0) {
- free(f);
- f = nil;
- }
-fail:
- thread->unlock(&mux->rlock);
- return f;
-}
-
-static void
-dispatchandqlock(IxpClient *mux, Fcall *f)
-{
- int tag;
- IxpRpc *r2;
-
- tag = f->hdr.tag - mux->mintag;
- thread->lock(&mux->lk);
- /* hand packet to correct sleeper */
- if(tag < 0 || tag >= mux->mwait) {
- fprintf(stderr, "libixp: recieved unfeasible tag: %d (min: %d, max: %d)\n", f->hdr.tag, mux->mintag, mux->mintag+mux->mwait);
- goto fail;
- }
- r2 = mux->wait[tag];
- if(r2 == nil || r2->prev == nil) {
- fprintf(stderr, "libixp: recieved message with bad tag\n");
- goto fail;
- }
- r2->p = f;
- dequeue(mux, r2);
- thread->wake(&r2->r);
- return;
-fail:
- ixp_freefcall(f);
- free(f);
-}
-
-static void
-electmuxer(IxpClient *mux)
-{
- IxpRpc *rpc;
-
- /* if there is anyone else sleeping, wake them to mux */
- for(rpc=mux->sleep.next; rpc != &mux->sleep; rpc = rpc->next){
- if(!rpc->async){
- mux->muxer = rpc;
- thread->wake(&rpc->r);
- return;
- }
- }
- mux->muxer = nil;
-}
-
-Fcall*
-muxrpc(IxpClient *mux, Fcall *tx)
-{
- IxpRpc r;
- Fcall *p;
-
- initrpc(mux, &r);
- if(sendrpc(&r, tx) < 0)
- return nil;
-
- thread->lock(&mux->lk);
- /* wait for our packet */
- while(mux->muxer && mux->muxer != &r && !r.p)
- thread->sleep(&r.r);
-
- /* if not done, there's no muxer; start muxing */
- if(!r.p){
- assert(mux->muxer == nil || mux->muxer == &r);
- mux->muxer = &r;
- while(!r.p){
- thread->unlock(&mux->lk);
- p = muxrecv(mux);
- if(p == nil){
- /* eof -- just give up and pass the buck */
- thread->lock(&mux->lk);
- dequeue(mux, &r);
- break;
- }
- dispatchandqlock(mux, p);
- }
- electmuxer(mux);
- }
- p = r.p;
- puttag(mux, &r);
- thread->unlock(&mux->lk);
- if(p == nil)
- werrstr("unexpected eof");
- return p;
-}
-
-static void
-enqueue(IxpClient *mux, IxpRpc *r)
-{
- r->next = mux->sleep.next;
- r->prev = &mux->sleep;
- r->next->prev = r;
- r->prev->next = r;
-}
-
-static void
-dequeue(IxpClient *mux, IxpRpc *r)
-{
- r->next->prev = r->prev;
- r->prev->next = r->next;
- r->prev = nil;
- r->next = nil;
-}
-
-static int
-gettag(IxpClient *mux, IxpRpc *r)
-{
- int i, mw;
- IxpRpc **w;
-
- for(;;){
- /* wait for a free tag */
- while(mux->nwait == mux->mwait){
- if(mux->mwait < mux->maxtag-mux->mintag){
- mw = mux->mwait;
- if(mw == 0)
- mw = 1;
- else
- mw <<= 1;
- w = realloc(mux->wait, mw * sizeof *w);
- if(w == nil)
- return -1;
- memset(w+mux->mwait, 0, (mw-mux->mwait) * sizeof *w);
- mux->wait = w;
- mux->freetag = mux->mwait;
- mux->mwait = mw;
- break;
- }
- thread->sleep(&mux->tagrend);
- }
-
- i=mux->freetag;
- if(mux->wait[i] == 0)
- goto Found;
- for(; i<mux->mwait; i++)
- if(mux->wait[i] == 0)
- goto Found;
- for(i=0; i<mux->freetag; i++)
- if(mux->wait[i] == 0)
- goto Found;
- /* should not fall out of while without free tag */
- abort();
- }
-
-Found:
- mux->nwait++;
- mux->wait[i] = r;
- r->tag = i+mux->mintag;
- return r->tag;
-}
-
-static void
-puttag(IxpClient *mux, IxpRpc *r)
-{
- int i;
-
- i = r->tag - mux->mintag;
- assert(mux->wait[i] == r);
- mux->wait[i] = nil;
- mux->nwait--;
- mux->freetag = i;
- thread->wake(&mux->tagrend);
- freemuxrpc(r);
-}
-
diff --git a/libixp/server.c b/libixp/server.c
@@ -1,165 +0,0 @@
-/* Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
- * See LICENSE file for license details.
- */
-#include <assert.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-/**
- * Function: ixp_listen
- *
- * Params:
- * fs - The file descriptor on which to listen.
- * aux - A piece of data to store in the connection's
- * T<IxpConn> data structure.
- * read - The function to call when the connection has
- * data available to read.
- * close - A cleanup function to call when the
- * connection is closed.
- *
- * Starts the server P<s> listening on P<fd>. The optional
- * callbacks are called as described, with the connections
- * T<IxpConn> data structure as their arguments.
- *
- * Returns:
- * Returns the connection's new T<IxpConn> data
- * structure.
- *
- * S<IxpConn>
- */
-IxpConn*
-ixp_listen(IxpServer *s, int fd, void *aux,
- void (*read)(IxpConn *c),
- void (*close)(IxpConn *c)
- ) {
- IxpConn *c;
-
- c = emallocz(sizeof *c);
- c->fd = fd;
- c->aux = aux;
- c->srv = s;
- c->read = read;
- c->close = close;
- c->next = s->conn;
- s->conn = c;
- return c;
-}
-
-/**
- * Function: ixp_hangup
- * Function: ixp_server_close
- *
- * ixp_hangup closes a connection, and stops the server
- * listening on it. It calls the connection's close
- * function, if it exists. ixp_server_close calls ixp_hangup
- * on all of the connections on which the server is
- * listening.
- */
-
-void
-ixp_hangup(IxpConn *c) {
- IxpServer *s;
- IxpConn **tc;
-
- s = c->srv;
- for(tc=&s->conn; *tc; tc=&(*tc)->next)
- if(*tc == c) break;
- assert(*tc == c);
-
- *tc = c->next;
- c->closed = 1;
- if(c->close)
- c->close(c);
- else
- shutdown(c->fd, SHUT_RDWR);
-
- close(c->fd);
- free(c);
-}
-
-void
-ixp_server_close(IxpServer *s) {
- IxpConn *c, *next;
-
- for(c = s->conn; c; c = next) {
- next = c->next;
- ixp_hangup(c);
- }
-}
-
-static void
-prepare_select(IxpServer *s) {
- IxpConn *c;
-
- FD_ZERO(&s->rd);
- for(c = s->conn; c; c = c->next)
- if(c->read) {
- if(s->maxfd < c->fd)
- s->maxfd = c->fd;
- FD_SET(c->fd, &s->rd);
- }
-}
-
-static void
-handle_conns(IxpServer *s) {
- IxpConn *c, *n;
- for(c = s->conn; c; c = n) {
- n = c->next;
- if(FD_ISSET(c->fd, &s->rd))
- c->read(c);
- }
-}
-
-/**
- * Function: ixp_serverloop
- *
- * Enters the main loop of the server. Exits when
- * P<s>->running becomes false, or when select(2) returns an
- * error other than EINTR.
- *
- * S<IxpServer>
- *
- * Returns:
- * Returns 0 when the loop exits normally, and 1 when
- * it exits on error. V<errno> or the return value of
- * ixp_errbuf(3) may be inspected.
- *
- */
-
-int
-ixp_serverloop(IxpServer *s) {
- timeval *tvp;
- timeval tv;
- long timeout;
- int r;
-
- s->running = 1;
- thread->initmutex(&s->lk);
- while(s->running) {
- if(s->preselect)
- s->preselect(s);
-
- tvp = nil;
- timeout = ixp_nexttimer(s);
- if(timeout > 0) {
- tv.tv_sec = timeout/1000;
- tv.tv_usec = timeout%1000 * 1000;
- tvp = &tv;
- }
-
- prepare_select(s);
- r = thread->select(s->maxfd + 1, &s->rd, 0, 0, tvp);
- if(r < 0) {
- if(errno == EINTR)
- continue;
- return 1;
- }
- handle_conns(s);
- }
- return 0;
-}
-
diff --git a/libixp/socket.c b/libixp/socket.c
@@ -1,278 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * Copyright ©2004-2006 Anselm R. Garbe <garbeam at gmail dot com>
- * See LICENSE file for license details.
- */
-#include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-/* Note: These functions modify the strings that they are passed.
- * The lookup function duplicates the original string, so it is
- * not modified.
- */
-
-/* From FreeBSD's sys/su.h */
-#define SUN_LEN(su) \
- (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
-
-typedef struct addrinfo addrinfo;
-typedef struct sockaddr sockaddr;
-typedef struct sockaddr_un sockaddr_un;
-typedef struct sockaddr_in sockaddr_in;
-
-static char*
-get_port(char *addr) {
- char *s;
-
- s = strchr(addr, '!');
- if(s == nil) {
- werrstr("no port provided");
- return nil;
- }
-
- *s++ = '\0';
- if(*s == '\0') {
- werrstr("invalid port number");
- return nil;
- }
- return s;
-}
-
-static int
-sock_unix(char *address, sockaddr_un *sa, socklen_t *salen) {
- int fd;
-
- memset(sa, 0, sizeof *sa);
-
- sa->sun_family = AF_UNIX;
- strncpy(sa->sun_path, address, sizeof sa->sun_path);
- *salen = SUN_LEN(sa);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(fd < 0)
- return -1;
- return fd;
-}
-
-static int
-dial_unix(char *address) {
- sockaddr_un sa;
- socklen_t salen;
- int fd;
-
- fd = sock_unix(address, &sa, &salen);
- if(fd == -1)
- return fd;
-
- if(connect(fd, (sockaddr*) &sa, salen)) {
- close(fd);
- return -1;
- }
- return fd;
-}
-
-static int
-announce_unix(char *file) {
- const int yes = 1;
- sockaddr_un sa;
- socklen_t salen;
- int fd;
-
- signal(SIGPIPE, SIG_IGN);
-
- fd = sock_unix(file, &sa, &salen);
- if(fd == -1)
- return fd;
-
- if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof yes) < 0)
- goto fail;
-
- unlink(file);
- if(bind(fd, (sockaddr*)&sa, salen) < 0)
- goto fail;
-
- chmod(file, S_IRWXU);
- if(listen(fd, IXP_MAX_CACHE) < 0)
- goto fail;
-
- return fd;
-
-fail:
- close(fd);
- return -1;
-}
-
-static addrinfo*
-alookup(char *host, int announce) {
- addrinfo hints, *ret;
- char *port;
- int err;
-
- /* Truncates host at '!' */
- port = get_port(host);
- if(port == nil)
- return nil;
-
- memset(&hints, 0, sizeof hints);
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
-
- if(announce) {
- hints.ai_flags = AI_PASSIVE;
- if(!strcmp(host, "*"))
- host = nil;
- }
-
- err = getaddrinfo(host, port, &hints, &ret);
- if(err) {
- werrstr("getaddrinfo: %s", gai_strerror(err));
- return nil;
- }
- return ret;
-}
-
-static int
-ai_socket(addrinfo *ai) {
- return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
-}
-
-static int
-dial_tcp(char *host) {
- addrinfo *ai, *aip;
- int fd;
-
- aip = alookup(host, 0);
- if(aip == nil)
- return -1;
-
- SET(fd);
- for(ai = aip; ai; ai = ai->ai_next) {
- fd = ai_socket(ai);
- if(fd == -1) {
- werrstr("socket: %s", strerror(errno));
- continue;
- }
-
- if(connect(fd, ai->ai_addr, ai->ai_addrlen) == 0)
- break;
-
- werrstr("connect: %s", strerror(errno));
- close(fd);
- fd = -1;
- }
-
- freeaddrinfo(aip);
- return fd;
-}
-
-static int
-announce_tcp(char *host) {
- addrinfo *ai, *aip;
- int fd;
-
- aip = alookup(host, 1);
- if(aip == nil)
- return -1;
-
- /* Probably don't need to loop */
- SET(fd);
- for(ai = aip; ai; ai = ai->ai_next) {
- fd = ai_socket(ai);
- if(fd == -1)
- continue;
-
- if(bind(fd, ai->ai_addr, ai->ai_addrlen) < 0)
- goto fail;
-
- if(listen(fd, IXP_MAX_CACHE) < 0)
- goto fail;
- break;
- fail:
- close(fd);
- fd = -1;
- }
-
- freeaddrinfo(aip);
- return fd;
-}
-
-typedef struct addrtab addrtab;
-static
-struct addrtab {
- char *type;
- int (*fn)(char*);
-} dtab[] = {
- {"tcp", dial_tcp},
- {"unix", dial_unix},
- {0, 0}
-}, atab[] = {
- {"tcp", announce_tcp},
- {"unix", announce_unix},
- {0, 0}
-};
-
-static int
-lookup(const char *address, addrtab *tab) {
- char *addr, *type;
- int ret;
-
- ret = -1;
- type = estrdup(address);
-
- addr = strchr(type, '!');
- if(addr == nil)
- werrstr("no address type defined");
- else {
- *addr++ = '\0';
- for(; tab->type; tab++)
- if(strcmp(tab->type, type) == 0) break;
- if(tab->type == nil)
- werrstr("unsupported address type");
- else
- ret = tab->fn(addr);
- }
-
- free(type);
- return ret;
-}
-
-/**
- * Function: ixp_dial
- * Function: ixp_announce
- *
- * Params:
- * address - An address on which to connect or listen,
- * specified in the Plan 9 resources
- * specification format
- * (<protocol>!address[!<port>])
- *
- * These functions hide some of the ugliness of Berkely
- * Sockets. ixp_dial connects to the resource at P<address>,
- * while ixp_announce begins listening on P<address>.
- *
- * Returns:
- * These functions return file descriptors on success,
- * and -1 on failure. ixp_errbuf(3) may be inspected on
- * failure.
- */
-
-int
-ixp_dial(const char *address) {
- return lookup(address, dtab);
-}
-
-int
-ixp_announce(const char *address) {
- return lookup(address, atab);
-}
-
diff --git a/libixp/srv_util.c b/libixp/srv_util.c
@@ -1,457 +0,0 @@
-/* Copyright ©2006-2008 Kris Maglione <fbsdaemon at gmail dot com>
- * See LICENSE file for license details.
- */
-#include <assert.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-typedef void* IxpFileIdU;
-
-static char
- Enofile[] = "file not found";
-
-#include "ixp_srvutil.h"
-
-struct IxpQueue {
- IxpQueue* link;
- char* dat;
- long len;
-};
-
-/* Macros */
-#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
-
-/* Global Vars */
-/***************/
-static IxpFileId* free_fileid;
-
-/* Utility Functions */
-/**
- * Obtain an empty, reference counted IxpFileId struct.
- */
-IxpFileId*
-ixp_srv_getfile(void) {
- IxpFileId *file;
- int i;
-
- if(!free_fileid) {
- i = 15;
- file = emallocz(i * sizeof *file);
- for(; i; i--) {
- file->next = free_fileid;
- free_fileid = file++;
- }
- }
- file = free_fileid;
- free_fileid = file->next;
- file->p = nil;
- file->volatil = 0;
- file->nref = 1;
- file->next = nil;
- file->pending = false;
- return file;
-}
-
-/**
- * Decrease the reference count of the given IxpFileId,
- * and push it onto the free list when it reaches 0;
- */
-void
-ixp_srv_freefile(IxpFileId *f) {
- if(--f->nref)
- return;
- free(f->tab.name);
- f->next = free_fileid;
- free_fileid = f;
-}
-
-/**
- * Increase the reference count of every IxpFileId linked
- * to 'f'.
- */
-IxpFileId*
-ixp_srv_clonefiles(IxpFileId *f) {
- IxpFileId *r;
-
- r = emalloc(sizeof *r);
- memcpy(r, f, sizeof *r);
- r->tab.name = estrdup(r->tab.name);
- r->nref = 1;
- for(f=f->next; f; f=f->next)
- assert(f->nref++);
- return r;
-}
-
-void
-ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len) {
-
- if(req->ifcall.io.offset >= len)
- return;
-
- len -= req->ifcall.io.offset;
- if(len > req->ifcall.io.count)
- len = req->ifcall.io.count;
- req->ofcall.io.data = emalloc(len);
- memcpy(req->ofcall.io.data, buf + req->ifcall.io.offset, len);
- req->ofcall.io.count = len;
-}
-
-void
-ixp_srv_writebuf(Ixp9Req *req, char **buf, uint *len, uint max) {
- IxpFileId *file;
- char *p;
- uint offset, count;
-
- file = req->fid->aux;
-
- offset = req->ifcall.io.offset;
- if(file->tab.perm & DMAPPEND)
- offset = *len;
-
- if(offset > *len || req->ifcall.io.count == 0) {
- req->ofcall.io.count = 0;
- return;
- }
-
- count = req->ifcall.io.count;
- if(max && (offset + count > max))
- count = max - offset;
-
- *len = offset + count;
- if(max == 0)
- *buf = erealloc(*buf, *len + 1);
- p = *buf;
-
- memcpy(p+offset, req->ifcall.io.data, count);
- req->ofcall.io.count = count;
- p[offset+count] = '\0';
-}
-
-/**
- * Ensure that the data member of 'r' is null terminated,
- * removing any new line from its end.
- */
-void
-ixp_srv_data2cstring(Ixp9Req *req) {
- char *p, *q;
- uint i;
-
- i = req->ifcall.io.count;
- p = req->ifcall.io.data;
- if(i && p[i - 1] == '\n')
- i--;
- q = memchr(p, '\0', i);
- if(q)
- i = q - p;
-
- p = erealloc(req->ifcall.io.data, i+1);
- p[i] = '\0';
- req->ifcall.io.data = p;
-}
-
-char*
-ixp_srv_writectl(Ixp9Req *req, char* (*fn)(void*, IxpMsg*)) {
- char *err, *s, *p, c;
- IxpFileId *file;
- IxpMsg msg;
-
- file = req->fid->aux;
-
- ixp_srv_data2cstring(req);
- s = req->ifcall.io.data;
-
- err = nil;
- c = *s;
- while(c != '\0') {
- while(*s == '\n')
- s++;
- p = s;
- while(*p != '\0' && *p != '\n')
- p++;
- c = *p;
- *p = '\0';
-
- msg = ixp_message(s, p-s, 0);
- s = fn(file->p, &msg);
- if(s)
- err = s;
- s = p + 1;
- }
- return err;
-}
-
-void
-ixp_pending_respond(Ixp9Req *req) {
- IxpFileId *file;
- IxpPendingLink *p;
- IxpRequestLink *req_link;
- IxpQueue *queue;
-
- file = req->fid->aux;
- assert(file->pending);
- p = file->p;
- if(p->queue) {
- queue = p->queue;
- p->queue = queue->link;
- req->ofcall.io.data = queue->dat;
- req->ofcall.io.count = queue->len;
- if(req->aux) {
- req_link = req->aux;
- req_link->next->prev = req_link->prev;
- req_link->prev->next = req_link->next;
- free(req_link);
- }
- respond(req, nil);
- free(queue);
- }else {
- req_link = emallocz(sizeof *req_link);
- req_link->req = req;
- req_link->next = &p->pending->req;
- req_link->prev = req_link->next->prev;
- req_link->next->prev = req_link;
- req_link->prev->next = req_link;
- req->aux = req_link;
- }
-}
-
-void
-ixp_pending_write(IxpPending *pending, char *dat, long n) {
- IxpRequestLink req_link;
- IxpQueue **qp, *queue;
- IxpPendingLink *pp;
- IxpRequestLink *rp;
-
- if(n == 0)
- return;
-
- if(pending->req.next == nil) {
- pending->req.next = &pending->req;
- pending->req.prev = &pending->req;
- pending->fids.prev = &pending->fids;
- pending->fids.next = &pending->fids;
- }
-
- for(pp=pending->fids.next; pp != &pending->fids; pp=pp->next) {
- for(qp=&pp->queue; *qp; qp=&qp[0]->link)
- ;
- queue = emallocz(sizeof *queue);
- queue->dat = emalloc(n);
- memcpy(queue->dat, dat, n);
- queue->len = n;
- *qp = queue;
- }
-
- req_link.next = &req_link;
- req_link.prev = &req_link;
- if(pending->req.next != &pending->req) {
- req_link.next = pending->req.next;
- req_link.prev = pending->req.prev;
- pending->req.prev = &pending->req;
- pending->req.next = &pending->req;
- }
- req_link.prev->next = &req_link;
- req_link.next->prev = &req_link;
-
- while((rp = req_link.next) != &req_link)
- ixp_pending_respond(rp->req);
-}
-
-void
-ixp_pending_pushfid(IxpPending *pending, IxpFid *fid) {
- IxpPendingLink *pend_link;
- IxpFileId *file;
-
- if(pending->req.next == nil) {
- pending->req.next = &pending->req;
- pending->req.prev = &pending->req;
- pending->fids.prev = &pending->fids;
- pending->fids.next = &pending->fids;
- }
-
- file = fid->aux;
- pend_link = emallocz(sizeof *pend_link);
- pend_link->fid = fid;
- pend_link->pending = pending;
- pend_link->next = &pending->fids;
- pend_link->prev = pend_link->next->prev;
- pend_link->next->prev = pend_link;
- pend_link->prev->next = pend_link;
- file->pending = true;
- file->p = pend_link;
-}
-
-static void
-pending_flush(Ixp9Req *req) {
- IxpFileId *file;
- IxpRequestLink *req_link;
-
- file = req->fid->aux;
- if(file->pending) {
- req_link = req->aux;
- if(req_link) {
- req_link->prev->next = req_link->next;
- req_link->next->prev = req_link->prev;
- free(req_link);
- }
- }
-}
-
-void
-ixp_pending_flush(Ixp9Req *req) {
-
- pending_flush(req->oldreq);
-}
-
-bool
-ixp_pending_clunk(Ixp9Req *req) {
- IxpPending *pending;
- IxpPendingLink *pend_link;
- IxpRequestLink *req_link;
- Ixp9Req *r;
- IxpFileId *file;
- IxpQueue *queue;
- bool more;
-
- file = req->fid->aux;
- pend_link = file->p;
-
- pending = pend_link->pending;
- for(req_link=pending->req.next; req_link != &pending->req;) {
- r = req_link->req;
- req_link = req_link->next;
- if(r->fid == pend_link->fid) {
- pending_flush(r);
- respond(r, "interrupted");
- }
- }
-
- pend_link->prev->next = pend_link->next;
- pend_link->next->prev = pend_link->prev;
-
- while((queue = pend_link->queue)) {
- pend_link->queue = queue->link;
- free(queue->dat);
- free(queue);
- }
- more = (pend_link->pending->fids.next == &pend_link->pending->fids);
- free(pend_link);
- respond(req, nil);
- return more;
-}
-
-bool
-ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup) {
- IxpFileId *tfile;
- int ret;
-
- if(!file->next)
- return true;
-
- ret = false;
- if(ixp_srv_verifyfile(file->next, lookup)) {
- tfile = lookup(file->next, file->tab.name);
- if(tfile) {
- if(!tfile->volatil || tfile->p == file->p)
- ret = true;
- ixp_srv_freefile(tfile);
- }
- }
- return ret;
-}
-
-void
-ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(IxpStat*, IxpFileId*)) {
- IxpMsg msg;
- IxpFileId *file, *tfile;
- IxpStat stat;
- char *buf;
- ulong size, n;
- uvlong offset;
-
- file = req->fid->aux;
-
- size = req->ifcall.io.count;
- if(size > req->fid->iounit)
- size = req->fid->iounit;
- buf = emallocz(size);
- msg = ixp_message(buf, size, MsgPack);
-
- file = lookup(file, nil);
- tfile = file;
- /* Note: The first file is ".", so we skip it. */
- offset = 0;
- for(file=file->next; file; file=file->next) {
- dostat(&stat, file);
- n = ixp_sizeof_stat(&stat);
- if(offset >= req->ifcall.io.offset) {
- if(size < n)
- break;
- ixp_pstat(&msg, &stat);
- size -= n;
- }
- offset += n;
- }
- while((file = tfile)) {
- tfile=tfile->next;
- ixp_srv_freefile(file);
- }
- req->ofcall.io.count = msg.pos - msg.data;
- req->ofcall.io.data = msg.data;
- respond(req, nil);
-}
-
-void
-ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup) {
- IxpFileId *file, *tfile;
- int i;
-
- file = ixp_srv_clonefiles(req->fid->aux);
- for(i=0; i < req->ifcall.twalk.nwname; i++) {
- if(!strcmp(req->ifcall.twalk.wname[i], "..")) {
- if(file->next) {
- tfile=file;
- file=file->next;
- ixp_srv_freefile(tfile);
- }
- }else{
- tfile = lookup(file, req->ifcall.twalk.wname[i]);
- if(!tfile)
- break;
- assert(!tfile->next);
- if(strcmp(req->ifcall.twalk.wname[i], ".")) {
- tfile->next = file;
- file = tfile;
- }
- }
- req->ofcall.rwalk.wqid[i].type = file->tab.qtype;
- req->ofcall.rwalk.wqid[i].path = QID(file->tab.type, file->id);
- }
- /* There should be a way to do this on freefid() */
- if(i < req->ifcall.twalk.nwname) {
- while((tfile = file)) {
- file=file->next;
- ixp_srv_freefile(tfile);
- }
- respond(req, Enofile);
- return;
- }
- /* Remove refs for req->fid if no new fid */
- if(req->ifcall.hdr.fid == req->ifcall.twalk.newfid) {
- tfile = req->fid->aux;
- req->fid->aux = file;
- while((file = tfile)) {
- tfile = tfile->next;
- ixp_srv_freefile(file);
- }
- }else
- req->newfid->aux = file;
- req->ofcall.rwalk.nwqid = i;
- respond(req, nil);
-}
-
diff --git a/libixp/thread.c b/libixp/thread.c
@@ -1,97 +0,0 @@
-/* Public Domain --Kris Maglione */
-#include <unistd.h>
-#include "ixp_local.h"
-
-static IxpThread ixp_nothread;
-IxpThread*ixp_thread = &ixp_nothread;
-
-static char*
-errbuf(void) {
- static char errbuf[IXP_ERRMAX];
-
- return errbuf;
-}
-
-static void
-mvoid(IxpMutex *m) {
- USED(m);
- return;
-}
-
-static int
-mtrue(IxpMutex *m) {
- USED(m);
- return 1;
-}
-
-static int
-mfalse(IxpMutex *m) {
- USED(m);
- return 0;
-}
-
-static void
-rwvoid(IxpRWLock *rw) {
- USED(rw);
- return;
-}
-
-static int
-rwtrue(IxpRWLock *rw) {
- USED(rw);
- return 1;
-}
-
-static int
-rwfalse(IxpRWLock *m) {
- USED(m);
- return 0;
-}
-
-static void
-rvoid(IxpRendez *r) {
- USED(r);
- return;
-}
-
-static int
-rfalse(IxpRendez *r) {
- USED(r);
- return 0;
-}
-
-static void
-rsleep(IxpRendez *r) {
- USED(r);
- eprint("rsleep called when not implemented\n");
-}
-
-static IxpThread ixp_nothread = {
- /* RWLock */
- .initrwlock = rwfalse,
- .rlock = rwvoid,
- .runlock = rwvoid,
- .canrlock = rwtrue,
- .wlock = rwvoid,
- .wunlock = rwvoid,
- .canwlock = rwtrue,
- .rwdestroy = rwvoid,
- /* Mutex */
- .initmutex = mfalse,
- .lock = mvoid,
- .unlock = mvoid,
- .canlock = mtrue,
- .mdestroy = mvoid,
- /* Rendez */
- .initrendez = rfalse,
- .sleep = rsleep,
- .wake = rfalse,
- .wakeall = rfalse,
- .rdestroy = rvoid,
- /* Other */
- .errbuf = errbuf,
- .read = read,
- .write = write,
- .select = select,
-};
-
diff --git a/libixp/timer.c b/libixp/timer.c
@@ -1,139 +0,0 @@
-/* Copyright ©2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <assert.h>
-#include <stdlib.h>
-#include <sys/time.h>
-#include "ixp_local.h"
-
-/* This really needn't be threadsafe, as it has little use in
- * threaded programs, but it is, nonetheless.
- */
-
-static long lastid = 1;
-
-/**
- * Function: ixp_msec
- *
- * Returns:
- * Returns the time since the Epoch in milliseconds.
- * Be aware that this may overflow.
- */
-long
-ixp_msec(void) {
- timeval tv;
-
- if(gettimeofday(&tv, 0) < 0)
- return -1;
- return tv.tv_sec*1000 + tv.tv_usec/1000;
-}
-
-/**
- * Function: ixp_settimer
- *
- * Params:
- * msec - The timeout in milliseconds.
- * fn - The function to call after P<msec> milliseconds
- * have elapsed.
- * aux - An arbitrary argument to pass to P<fn> when it
- * is called.
- *
- * Initializes a callback-based timer to be triggerred after
- * P<msec> milliseconds. The timer is passed its id number
- * and the value of P<aux>.
- *
- * Returns:
- * Returns the new timer's unique id number.
- */
-long
-ixp_settimer(IxpServer *s, long msec, void (*fn)(long, void*), void *aux) {
- Timer **tp;
- Timer *t;
- long time;
-
- time = ixp_msec();
- if(time == -1)
- return -1;
- msec += time;
-
- t = emallocz(sizeof *t);
- thread->lock(&s->lk);
- t->id = lastid++;
- t->msec = msec;
- t->fn = fn;
- t->aux = aux;
-
- for(tp=&s->timer; *tp; tp=&tp[0]->link)
- if(tp[0]->msec < msec)
- break;
- t->link = *tp;
- *tp = t;
- thread->unlock(&s->lk);
- return t->id;
-}
-
-/**
- * Function: ixp_unsettimer
- *
- * Params:
- * id - The id number of the timer to void.
- *
- * Voids the timer identified by P<id>.
- *
- * Returns:
- * Returns true if a timer was stopped, false
- * otherwise.
- */
-int
-ixp_unsettimer(IxpServer *s, long id) {
- Timer **tp;
- Timer *t;
-
- thread->lock(&s->lk);
- for(tp=&s->timer; (t=*tp); tp=&t->link)
- if(t->id == id)
- break;
- if(t) {
- *tp = t->link;
- free(t);
- }
- thread->unlock(&s->lk);
- return t != nil;
-}
-
-/**
- * Function: ixp_nexttimer
- *
- * Triggers any timers whose timeouts have ellapsed. This is
- * primarilly intended to be called from libixp's select
- * loop.
- *
- * Returns:
- * Returns the number of milliseconds until the next
- * timer's timeout.
- */
-long
-ixp_nexttimer(IxpServer *s) {
- Timer *t;
- long time, ret;
-
- SET(time);
- thread->lock(&s->lk);
- while((t = s->timer)) {
- time = ixp_msec();
- if(t->msec > time)
- break;
- s->timer = t->link;
-
- thread->unlock(&s->lk);
- t->fn(t->id, t->aux);
- free(t);
- thread->lock(&s->lk);
- }
- ret = 0;
- if(t)
- ret = t->msec - time;
- thread->unlock(&s->lk);
- return ret;
-}
-
diff --git a/libixp/transport.c b/libixp/transport.c
@@ -1,97 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-static int
-mread(int fd, IxpMsg *msg, uint count) {
- int r, n;
-
- n = msg->end - msg->pos;
- if(n <= 0) {
- werrstr("buffer full");
- return -1;
- }
- if(n > count)
- n = count;
-
- r = thread->read(fd, msg->pos, n);
- if(r > 0)
- msg->pos += r;
- return r;
-}
-
-static int
-readn(int fd, IxpMsg *msg, uint count) {
- uint num;
- int r;
-
- num = count;
- while(num > 0) {
- r = mread(fd, msg, num);
- if(r == -1 && errno == EINTR)
- continue;
- if(r == 0) {
- werrstr("broken pipe: %s", ixp_errbuf());
- return count - num;
- }
- num -= r;
- }
- return count - num;
-}
-
-uint
-ixp_sendmsg(int fd, IxpMsg *msg) {
- int r;
-
- msg->pos = msg->data;
- while(msg->pos < msg->end) {
- r = thread->write(fd, msg->pos, msg->end - msg->pos);
- if(r < 1) {
- if(errno == EINTR)
- continue;
- werrstr("broken pipe: %s", ixp_errbuf());
- return 0;
- }
- msg->pos += r;
- }
- return msg->pos - msg->data;
-}
-
-uint
-ixp_recvmsg(int fd, IxpMsg *msg) {
- enum { SSize = 4 };
- ulong msize, size;
-
- msg->mode = MsgUnpack;
- msg->pos = msg->data;
- msg->end = msg->data + msg->size;
- if(readn(fd, msg, SSize) != SSize)
- return 0;
-
- msg->pos = msg->data;
- ixp_pu32(msg, &msize);
-
- size = msize - SSize;
- if(size >= msg->end - msg->pos) {
- werrstr("message too large");
- return 0;
- }
- if(readn(fd, msg, size) != size) {
- werrstr("message incomplete");
- return 0;
- }
-
- msg->end = msg->pos;
- return msize;
-}
-
diff --git a/libixp/util.c b/libixp/util.c
@@ -1,240 +0,0 @@
-/* Written by Kris Maglione <fbsdaemon at gmail dot com> */
-/* Public domain */
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <pwd.h>
-#include "ixp_local.h"
-
-char*
-ixp_smprint(const char *fmt, ...) {
- va_list ap;
- char *s;
-
- va_start(ap, fmt);
- s = ixp_vsmprint(fmt, ap);
- va_end(ap);
- if(s == nil)
- ixp_werrstr("no memory");
- return s;
-}
-
-static char*
-_user(void) {
- static char *user;
- struct passwd *pw;
-
- if(user == nil) {
- pw = getpwuid(getuid());
- if(pw)
- user = strdup(pw->pw_name);
- }
- if(user == nil)
- user = "none";
- return user;
-}
-
-static int
-rmkdir(char *path, int mode) {
- char *p;
- int ret;
- char c;
-
- for(p = path+1; ; p++) {
- c = *p;
- if((c == '/') || (c == '\0')) {
- *p = '\0';
- ret = mkdir(path, mode);
- if((ret == -1) && (errno != EEXIST)) {
- ixp_werrstr("Can't create path '%s': %s", path, ixp_errbuf());
- return 0;
- }
- *p = c;
- }
- if(c == '\0')
- break;
- }
- return 1;
-}
-
-static char*
-ns_display(void) {
- char *path, *disp;
- struct stat st;
-
- disp = getenv("DISPLAY");
- if(disp == nil || disp[0] == '\0') {
- ixp_werrstr("$DISPLAY is unset");
- return nil;
- }
-
- disp = estrdup(disp);
- path = &disp[strlen(disp) - 2];
- if(path > disp && !strcmp(path, ".0"))
- *path = '\0';
-
- path = ixp_smprint("/tmp/ns.%s.%s", _user(), disp);
- free(disp);
-
- if(!rmkdir(path, 0700))
- ;
- else if(stat(path, &st))
- ixp_werrstr("Can't stat ns_path '%s': %s", path, ixp_errbuf());
- else if(getuid() != st.st_uid)
- ixp_werrstr("ns_path '%s' exists but is not owned by you", path);
- else if((st.st_mode & 077) && chmod(path, st.st_mode & ~077))
- ixp_werrstr("Namespace path '%s' exists, but has wrong permissions: %s", path, ixp_errbuf());
- else
- return path;
- free(path);
- return nil;
-}
-
-/**
- * Function: ixp_namespace
- *
- * Returns the path of the canonical 9p namespace directory.
- * Either the value of $NAMESPACE, if it's set, or, roughly,
- * /tmp/ns.${USER}.${DISPLAY:%.0=%}. In the latter case, the
- * directory is created if it doesn't exist, and it is
- * ensured to be owned by the current user, with no group or
- * other permissions.
- *
- * Returns:
- * A statically allocated string which must not be freed
- * or altered by the caller. The same value is returned
- * upon successive calls.
- */
-/* Not especially threadsafe. */
-char*
-ixp_namespace(void) {
- static char *namespace;
-
- if(namespace == nil)
- namespace = getenv("NAMESPACE");
- if(namespace == nil)
- namespace = ns_display();
- return namespace;
-}
-
-void
-eprint(const char *fmt, ...) {
- va_list ap;
- int err;
-
- err = errno;
- fprintf(stderr, "libixp: fatal: ");
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- if(fmt[strlen(fmt)-1] == ':')
- fprintf(stderr, " %s\n", strerror(err));
- else
- fprintf(stderr, "\n");
-
- exit(1);
-}
-
-/* Can't malloc */
-static void
-mfatal(char *name, uint size) {
- const char
- couldnot[] = "libixp: fatal: Could not ",
- paren[] = "() ",
- bytes[] = " bytes\n";
- char sizestr[8];
- int i;
-
- i = sizeof sizestr;
- do {
- sizestr[--i] = '0' + (size%10);
- size /= 10;
- } while(size > 0);
-
- write(1, couldnot, sizeof(couldnot)-1);
- write(1, name, strlen(name));
- write(1, paren, sizeof(paren)-1);
- write(1, sizestr+i, sizeof(sizestr)-i);
- write(1, bytes, sizeof(bytes)-1);
-
- exit(1);
-}
-
-void*
-emalloc(uint size) {
- void *ret = malloc(size);
- if(!ret)
- mfatal("malloc", size);
- return ret;
-}
-
-void*
-emallocz(uint size) {
- void *ret = emalloc(size);
- memset(ret, 0, size);
- return ret;
-}
-
-void*
-erealloc(void *ptr, uint size) {
- void *ret = realloc(ptr, size);
- if(!ret)
- mfatal("realloc", size);
- return ret;
-}
-
-char*
-estrdup(const char *str) {
- void *ret = strdup(str);
- if(!ret)
- mfatal("strdup", strlen(str));
- return ret;
-}
-
-uint
-tokenize(char *res[], uint reslen, char *str, char delim) {
- char *s;
- uint i;
-
- i = 0;
- s = str;
- while(i < reslen && *s) {
- while(*s == delim)
- *(s++) = '\0';
- if(*s)
- res[i++] = s;
- while(*s && *s != delim)
- s++;
- }
- return i;
-}
-
-uint
-strlcat(char *dst, const char *src, uint size) {
- const char *s;
- char *d;
- int n, len;
-
- d = dst;
- s = src;
- n = size;
- while(n-- > 0 && *d != '\0')
- d++;
- len = n;
-
- while(*s != '\0' && n-- > 0)
- *d++ = *s++;
- while(*s++ != '\0')
- n--;
- if(len > 0)
- *d = '\0';
- return size - n - 1;
-}
-
diff --git a/libixp_pthread/Makefile b/libixp_pthread/Makefile
@@ -1,10 +0,0 @@
-ROOT= ..
-include ${ROOT}/mk/hdr.mk
-include ${ROOT}/mk/ixp.mk
-
-TARG = libixp_pthread
-
-OBJ = thread_pthread
-
-include ${ROOT}/mk/lib.mk
-
diff --git a/libixp_pthread/thread_pthread.c b/libixp_pthread/thread_pthread.c
@@ -1,184 +0,0 @@
-/* Written by Kris Maglione <fbsdaemon@gmail.com> */
-/* Public domain */
-#define _XOPEN_SOURCE 600
-#include <errno.h>
-#include <pthread.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include "ixp_local.h"
-
-static IxpThread ixp_pthread;
-static pthread_key_t errstr_k;
-
-int
-ixp_pthread_init() {
- int ret;
-
- ret = pthread_key_create(&errstr_k, free);
- if(ret) {
- werrstr("can't create TLS value: %s", ixp_errbuf());
- return 1;
- }
-
- ixp_thread = &ixp_pthread;
- return 0;
-}
-
-static char*
-errbuf(void) {
- char *ret;
-
- ret = pthread_getspecific(errstr_k);
- if(ret == nil) {
- ret = emallocz(IXP_ERRMAX);
- pthread_setspecific(errstr_k, (void*)ret);
- }
- return ret;
-}
-
-static void
-mlock(IxpMutex *m) {
- pthread_mutex_lock(m->aux);
-}
-
-static int
-mcanlock(IxpMutex *m) {
- return !pthread_mutex_trylock(m->aux);
-}
-
-static void
-munlock(IxpMutex *m) {
- pthread_mutex_unlock(m->aux);
-}
-
-static void
-mdestroy(IxpMutex *m) {
- pthread_mutex_destroy(m->aux);
- free(m->aux);
-}
-
-static int
-initmutex(IxpMutex *m) {
- pthread_mutex_t *mutex;
-
- mutex = emalloc(sizeof *mutex);
- if(pthread_mutex_init(mutex, nil)) {
- free(mutex);
- return 1;
- }
-
- m->aux = mutex;
- return 0;
-}
-
-static void
-rlock(IxpRWLock *rw) {
- pthread_rwlock_rdlock(rw->aux);
-}
-
-static int
-canrlock(IxpRWLock *rw) {
- return !pthread_rwlock_tryrdlock(rw->aux);
-}
-
-static void
-wlock(IxpRWLock *rw) {
- pthread_rwlock_rdlock(rw->aux);
-}
-
-static int
-canwlock(IxpRWLock *rw) {
- return !pthread_rwlock_tryrdlock(rw->aux);
-}
-
-static void
-rwunlock(IxpRWLock *rw) {
- pthread_rwlock_unlock(rw->aux);
-}
-
-static void
-rwdestroy(IxpRWLock *rw) {
- pthread_rwlock_destroy(rw->aux);
- free(rw->aux);
-}
-
-static int
-initrwlock(IxpRWLock *rw) {
- pthread_rwlock_t *rwlock;
-
- rwlock = emalloc(sizeof *rwlock);
- if(pthread_rwlock_init(rwlock, nil)) {
- free(rwlock);
- return 1;
- }
-
- rw->aux = rwlock;
- return 0;
-}
-
-static void
-rsleep(IxpRendez *r) {
- pthread_cond_wait(r->aux, r->mutex->aux);
-}
-
-static int
-rwake(IxpRendez *r) {
- pthread_cond_signal(r->aux);
- return 0;
-}
-
-static int
-rwakeall(IxpRendez *r) {
- pthread_cond_broadcast(r->aux);
- return 0;
-}
-
-static void
-rdestroy(IxpRendez *r) {
- pthread_cond_destroy(r->aux);
- free(r->aux);
-}
-
-static int
-initrendez(IxpRendez *r) {
- pthread_cond_t *cond;
-
- cond = emalloc(sizeof *cond);
- if(pthread_cond_init(cond, nil)) {
- free(cond);
- return 1;
- }
-
- r->aux = cond;
- return 0;
-}
-
-static IxpThread ixp_pthread = {
- /* Mutex */
- .initmutex = initmutex,
- .lock = mlock,
- .canlock = mcanlock,
- .unlock = munlock,
- .mdestroy = mdestroy,
- /* RWLock */
- .initrwlock = initrwlock,
- .rlock = rlock,
- .canrlock = canrlock,
- .wlock = wlock,
- .canwlock = canwlock,
- .runlock = rwunlock,
- .wunlock = rwunlock,
- .rwdestroy = rwdestroy,
- /* Rendez */
- .initrendez = initrendez,
- .sleep = rsleep,
- .wake = rwake,
- .wakeall = rwakeall,
- .rdestroy = rdestroy,
- /* Other */
- .errbuf = errbuf,
- .read = read,
- .write = write,
- .select = select,
-};
-
diff --git a/libixp_rubythread/Makefile b/libixp_rubythread/Makefile
@@ -1,11 +0,0 @@
-ROOT= ..
-include ${ROOT}/mk/hdr.mk
-include ${ROOT}/mk/ixp.mk
-
-CFLAGS += ${RUBYINC}
-
-TARG = libixp_rubythread
-OBJ = thread_ruby
-
-include ${ROOT}/mk/lib.mk
-
diff --git a/libixp_rubythread/thread_ruby.c b/libixp_rubythread/thread_ruby.c
@@ -1,281 +0,0 @@
-/* Copyright ©2007-2008 Kris Maglione <fbsdaemon@gmail.com>
- * See LICENSE file for license details.
- */
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ruby.h>
-#include "ixp_local.h"
-
-static IxpThread ixp_rthread;
-static char RWLock[];
-
-int
-ixp_rubyinit(void) {
- rb_require("thread.rb");
- rb_eval_string(RWLock);
- ixp_thread = &ixp_rthread;
- return 0;
-}
-
-static char*
-errbuf(void) {
- static ID key;
- volatile VALUE val;
-
- if(key == 0L)
- key = rb_intern("_ixp_errbuf");
-
- val = rb_thread_local_aref(rb_thread_current(), key);
- if(NIL_P(val)) {
- val = rb_str_new(nil, IXP_ERRMAX);
- rb_thread_local_aset(rb_thread_current(), key, val);
- }
-
- Check_Type(val, T_STRING);
- return RSTRING(val)->ptr;
-}
-
-static void
-save(char *eval, void **place) {
- *place = (void*)rb_eval_string(eval);
- rb_gc_register_address((VALUE*)place);
-}
-
-static void
-unsave(void **place) {
- rb_gc_unregister_address((VALUE*)place);
-}
-
-#define call(obj, meth, ...) rb_funcall((VALUE)obj, rb_intern(meth), __VA_ARGS__)
-
-/* Mutex */
-static int
-initmutex(IxpMutex *m) {
- save("Mutex.new", &m->aux);
- return 0;
-}
-
-static void
-mdestroy(IxpMutex *m) {
- unsave(&m->aux);
-}
-
-static void
-mlock(IxpMutex *m) {
- call(m->aux, "lock", 0);
-}
-
-static int
-mcanlock(IxpMutex *m) {
- return call(m->aux, "trylock", 0);
-}
-
-static void
-munlock(IxpMutex *m) {
- call(m->aux, "unlock", 0);
-}
-
-/* RWLock */
-static int
-initrwlock(IxpRWLock *rw) {
- save("RWLock.new", &rw->aux);
- return 0;
-}
-
-static void
-rwdestroy(IxpRWLock *rw) {
- unsave(&rw->aux);
-}
-
-static void
-rlock(IxpRWLock *rw) {
- call(rw->aux, "rdlock", 0);
-}
-
-static int
-canrlock(IxpRWLock *rw) {
- return call(rw->aux, "tryrdlock", 0) == Qtrue;
-}
-
-static void
-wlock(IxpRWLock *rw) {
- call(rw->aux, "wrlock", 0);
-}
-
-static int
-canwlock(IxpRWLock *rw) {
- return call(rw->aux, "trywrlock", 0) == Qtrue;
-}
-
-static void
-rwunlock(IxpRWLock *rw) {
- call(rw->aux, "unlock", 0);
-}
-
-/* Rendez */
-static int
-initrendez(IxpRendez *r) {
- save("ConditionVariable.new", &r->aux);
- return 0;
-}
-
-static void
-rdestroy(IxpRendez *r) {
- unsave(&r->aux);
-}
-
-static void
-rsleep(IxpRendez *r) {
- call(r->aux, "wait", 1, (VALUE)r->mutex->aux);
-}
-
-static int
-rwake(IxpRendez *r) {
- call(r->aux, "signal", 0);
- return 0;
-}
-
-static int
-rwakeall(IxpRendez *r) {
- call(r->aux, "broadcast", 0);
- return 0;
-}
-
-/* Yielding IO */
-static ssize_t
-_read(int fd, void *buf, size_t size) {
- int n;
-
- rb_thread_wait_fd(fd);
- n = read(fd, buf, size);
-
- if(n < 0 && errno == EINTR)
- rb_thread_schedule();
- return n;
-}
-
-static ssize_t
-_write(int fd, const void *buf, size_t size) {
- int n;
-
- rb_thread_fd_writable(fd);
- n = write(fd, buf, size);
-
- if(n < 0 && errno == EINTR)
- rb_thread_schedule();
- return n;
-}
-
-static IxpThread ixp_rthread = {
- /* Mutex */
- .initmutex = initmutex,
- .lock = mlock,
- .canlock = mcanlock,
- .unlock = munlock,
- .mdestroy = mdestroy,
- /* RWLock */
- .initrwlock = initrwlock,
- .rlock = rlock,
- .canrlock = canrlock,
- .wlock = wlock,
- .canwlock = canwlock,
- .runlock = rwunlock,
- .wunlock = rwunlock,
- .rwdestroy = rwdestroy,
- /* Rendez */
- .initrendez = initrendez,
- .sleep = rsleep,
- .wake = rwake,
- .wakeall = rwakeall,
- .rdestroy = rdestroy,
- /* Other */
- .errbuf = errbuf,
- .read = _read,
- .write = _write,
- .select = rb_thread_select,
-};
-
-static char RWLock[] =
- "class RWLock \n"
- " def initialize \n"
- " @rdqueue = [] \n"
- " @wrqueue = [] \n"
- " @wrheld = nil \n"
- " @rdheld = [] \n"
- " end \n"
- " \n"
- " def rdlock \n"
- " cr = Thread.critical \n"
- " while (Thread.critical = true; @wrheld != nil && @rwheld != Thread.current)\n"
- " @rdqueue.push Thread.current \n"
- " Thread.stop \n"
- " end \n"
- " @wrheld = nil \n"
- " @rdheld.push Thread.current \n"
- " \n"
- " @rdqueue.each {|t| t.wakeup} \n"
- " Thread.critical = cr \n"
- " self \n"
- " end \n"
- " \n"
- " def wrlock \n"
- " cr = Thread.critical \n"
- " while (Thread.critical = true; \n"
- " !@rdheld.empty? || (@wrheld != Thread.current && @wrheld != nil)) \n"
- " @wrqueue.push Thread.current \n"
- " Thread.stop \n"
- " end \n"
- " @wrheld = Thread.current \n"
- " Thread.critical = cr \n"
- " self \n"
- " end \n"
- " \n"
- " \n"
- " def tryrdlock \n"
- " cr = Thread.critical \n"
- " if @wrheld == nil \n"
- " rdlock \n"
- " true \n"
- " else \n"
- " false \n"
- " end \n"
- " ensure \n"
- " Thread.critical = cr \n"
- " end \n"
- " \n"
- " def trywrlock \n"
- " cr = Thread.critical \n"
- " if @wrheld == nil && @rdheld.empty? \n"
- " wrlock \n"
- " true \n"
- " else \n"
- " false \n"
- " end \n"
- " ensure \n"
- " Thread.critical = cr \n"
- " end \n"
- " \n"
- " def unlock \n"
- " cr = Thread.critical \n"
- " Thread.critical = true \n"
- " \n"
- " if @rdheld.include?(Thread.current) \n"
- " @rdheld.remove!(Thread.current) \n"
- " raise if @wrheld \n"
- " elsif @rwheld != Thread.current \n"
- " raise \n"
- " end \n"
- " \n"
- " @wrheld = nil \n"
- " if !@rwqueue.empty? && @rdheld.empty? \n"
- " @wrheld = @wrqueue.shift \n"
- " elsif !@rdqueue.empty \n"
- " @wrheld = @rdqueue.shift \n"
- " end \n"
- " @wrheld.wakeup if @wrheld \n"
- " ensure \n"
- " Thread.critical = cr \n"
- " end \n"
- "end \n";
-
diff --git a/libixp_task/Makefile b/libixp_task/Makefile
@@ -1,11 +0,0 @@
-ROOT= ..
-include ${ROOT}/mk/hdr.mk
-include ${ROOT}/mk/ixp.mk
-
-CFLAGS += ${TASKINC}
-
-TARG = libixp_task
-OBJ = thread_task
-
-include ${ROOT}/mk/lib.mk
-
diff --git a/libixp_task/thread_task.c b/libixp_task/thread_task.c
@@ -1,179 +0,0 @@
-/* Written by Kris Maglione <fbsdaemon@gmail.com> */
-/* Public domain */
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <task.h>
-#include "ixp_local.h"
-
-static IxpThread ixp_task;
-
-int
-ixp_taskinit() {
- ixp_thread = &ixp_task;
- return 0;
-}
-
-static char*
-errbuf(void) {
- void **p;
-
- p = taskdata();
- if(*p == nil)
- *p = emallocz(IXP_ERRMAX);
- return *p;
-}
-
-/* Mutex */
-static int
-initmutex(IxpMutex *m) {
- m->aux = emallocz(sizeof(QLock));
- return 0;
-}
-
-static void
-mdestroy(IxpMutex *m) {
- free(m->aux);
- m->aux = nil;
-}
-
-static void
-mlock(IxpMutex *m) {
- qlock(m->aux);
-}
-
-static int
-mcanlock(IxpMutex *m) {
- return canqlock(m->aux);
-}
-
-static void
-munlock(IxpMutex *m) {
- qunlock(m->aux);
-}
-
-/* RWLock */
-static int
-initrwlock(IxpRWLock *rw) {
- rw->aux = emallocz(sizeof(RWLock));
- return 0;
-}
-
-static void
-rwdestroy(IxpRWLock *rw) {
- free(rw->aux);
- rw->aux = nil;
-}
-
-static void
-_rlock(IxpRWLock *rw) {
- rlock(rw->aux);
-}
-
-static int
-_canrlock(IxpRWLock *rw) {
- return canrlock(rw->aux);
-}
-
-static void
-_wlock(IxpRWLock *rw) {
- wlock(rw->aux);
-}
-
-static int
-_canwlock(IxpRWLock *rw) {
- return canwlock(rw->aux);
-}
-
-static void
-_runlock(IxpRWLock *rw) {
- runlock(rw->aux);
-}
-
-static void
-_wunlock(IxpRWLock *rw) {
- wunlock(rw->aux);
-}
-
-/* Rendez */
-static int
-initrendez(IxpRendez *r) {
- r->aux = emallocz(sizeof(Rendez));
- return 0;
-}
-
-static void
-rdestroy(IxpRendez *r) {
- free(r->aux);
- r->aux = nil;
-}
-
-static void
-rsleep(IxpRendez *r) {
- Rendez *rz;
-
- rz = r->aux;
- rz->l = r->mutex->aux;
- tasksleep(rz);
-}
-
-static int
-rwake(IxpRendez *r) {
- Rendez *rz;
-
- rz = r->aux;
- rz->l = r->mutex->aux;
- return taskwakeup(rz);
-}
-
-static int
-rwakeall(IxpRendez *r) {
- Rendez *rz;
-
- rz = r->aux;
- rz->l = r->mutex->aux;
- return taskwakeupall(rz);
-}
-
-/* Yielding IO */
-static ssize_t
-_read(int fd, void *buf, size_t size) {
- fdnoblock(fd);
- return fdread(fd, buf, size);
-}
-
-static ssize_t
-_write(int fd, const void *buf, size_t size) {
- fdnoblock(fd);
- return fdwrite(fd, (void*)buf, size);
-}
-
-static IxpThread ixp_task = {
- /* Mutex */
- .initmutex = initmutex,
- .lock = mlock,
- .canlock = mcanlock,
- .unlock = munlock,
- .mdestroy = mdestroy,
- /* RWLock */
- .initrwlock = initrwlock,
- .rlock = _rlock,
- .canrlock = _canrlock,
- .wlock = _wlock,
- .canwlock = _canwlock,
- .runlock = _runlock,
- .wunlock = _wunlock,
- .rwdestroy = rwdestroy,
- /* Rendez */
- .initrendez = initrendez,
- .sleep = rsleep,
- .wake = rwake,
- .wakeall = rwakeall,
- .rdestroy = rdestroy,
- /* Other */
- .errbuf = errbuf,
- .read = _read,
- .write = _write,
- .select = select, /* wrong */
-};
-