commit c9664b1bccd3e65497502704fede2ad26423c12f
parent a5200bef5950630fd25a207ce180d8d302b058bb
Author: Kris Maglione <kris@suckless.org>
Date: Wed, 16 Jun 2010 15:48:34 -0400
Doc updates and minor API changes.
Diffstat:
64 files changed, 2047 insertions(+), 492 deletions(-)
diff --git a/NEWS b/NEWS
@@ -0,0 +1,7 @@
+
+0.6:
+ Add API documentation and manual pages.
+ Now fully MIT licensed.
+ Fix build problems on case insensitive filesystems.
+ Change ixp_srv_clonefiles specification.
+
diff --git a/include/ixp.h b/include/ixp.h
@@ -4,10 +4,11 @@
*/
#include <stdarg.h>
+#include <stdint.h>
#include <sys/types.h>
#include <sys/select.h>
-#define IXP_API 116
+#define IXP_API 127
/* Gunk */
#if defined(IXP_NEEDAPI) && IXP_API < IXP_NEEDAPI
@@ -17,18 +18,29 @@
# warning This version of libixp has a newer API than this compilation requires.
#endif
+#if defined(IXP_NEEDAPI) && IXP_NEEDAPI < 127
+# undef ushort
+# undef ulong
+# undef vlong
+# undef uvlong
+# define ushort _ixpushort
+# define ulong _ixpulong
+# define vlong _ixpvlong
+# define uvlong _ixpuvlong
+
+typedef uint16_t ushort;
+typedef uint32_t ulong;
+typedef uint64_t uvlong;
+
+typedef int64_t vlong;
+#endif
+
#undef uchar
-#undef ushort
#undef uint
-#undef ulong
-#undef vlong
-#undef uvlong
-#define uchar _ixpuchar
-#define ushort _ixpushort
-#define uint _ixpuint
-#define ulong _ixpulong
-#define vlong _ixpvlong
-#define uvlong _ixpuvlong
+#define uchar _ixpuchar
+#define uint _ixpuint
+typedef unsigned char uchar;
+typedef unsigned int uint;
#ifdef KENC
# define STRUCT(x) struct {x};
@@ -36,23 +48,11 @@
#elif defined(__GNUC__)
# define STRUCT(x) __extension__ struct {x};
# define UNION(x) __extension__ union {x};
-#else
-# define IXP_NEEDAPI 89
-# define STRUCT(x) x
-# define UNION(x) x
#endif
/* End Gunk */
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned long long uvlong;
-
-typedef long long vlong;
-
#define IXP_VERSION "9P2000"
-#define IXP_NOTAG ((ushort)~0) /* Dummy tag */
+#define IXP_NOTAG ((uint16_t)~0) /* Dummy tag */
#define IXP_NOFID (~0U)
enum {
@@ -244,44 +244,47 @@ enum {
};
struct IxpMutex {
- void* aux;
+ void* aux;
};
-struct IxpRWLock {
- void* aux;
+struct IxpRendez {
+ IxpMutex* mutex;
+ void* aux;
};
-struct IxpRendez {
- IxpMutex* mutex;
+struct IxpRWLock {
void* aux;
};
-enum { MsgPack, MsgUnpack, };
+enum IxpMsgMode {
+ MsgPack,
+ MsgUnpack,
+};
struct IxpMsg {
- char* data;
- char* pos;
- char* end;
- uint size;
- uint mode;
+ char* data; /* Begining of buffer. */
+ char* pos; /* Current position in buffer. */
+ char* end; /* End of message. */
+ uint size; /* Size of buffer. */
+ uint mode; /* MsgPack or MsgUnpack. */
};
struct IxpQid {
- uchar type;
- ulong version;
- uvlong path;
+ uint8_t type;
+ uint32_t version;
+ uint64_t path;
/* Private members */
- uchar dir_type;
+ uint8_t dir_type;
};
/* stat structure */
struct IxpStat {
- ushort type;
- ulong dev;
- IxpQid qid;
- ulong mode;
- ulong atime;
- ulong mtime;
- uvlong length;
+ uint16_t type;
+ uint32_t dev;
+ IxpQid qid;
+ uint32_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
char* name;
char* uid;
char* gid;
@@ -313,122 +316,122 @@ typedef struct IxpFIO IxpFIO;
typedef struct IxpFVersion IxpFVersion;
struct IxpFHdr {
- uchar type;
- ushort tag;
- ulong fid;
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
};
struct IxpFVersion {
- IxpFHdr hdr;
- ulong msize;
- char* version;
+ IxpFHdr hdr;
+ uint32_t msize;
+ char* version;
};
struct IxpFTFlush {
- IxpFHdr hdr;
- ushort oldtag;
+ IxpFHdr hdr;
+ uint16_t oldtag;
};
struct IxpFError {
- IxpFHdr hdr;
- char* ename;
+ IxpFHdr hdr;
+ char* ename;
};
struct IxpFROpen {
- IxpFHdr hdr;
- IxpQid qid; /* +Rattach */
- ulong iounit;
+ IxpFHdr hdr;
+ IxpQid qid; /* +Rattach */
+ uint32_t iounit;
};
struct IxpFRAuth {
- IxpFHdr hdr;
- IxpQid aqid;
+ IxpFHdr hdr;
+ IxpQid aqid;
};
struct IxpFAttach {
- IxpFHdr hdr;
- ulong afid;
- char* uname;
- char* aname;
+ IxpFHdr hdr;
+ uint32_t afid;
+ char* uname;
+ char* aname;
};
struct IxpFTCreate {
- IxpFHdr hdr;
- ulong perm;
- char* name;
- uchar mode; /* +Topen */
+ IxpFHdr hdr;
+ uint32_t perm;
+ char* name;
+ uint8_t mode; /* +Topen */
};
struct IxpFTWalk {
IxpFHdr hdr;
- ulong newfid;
- ushort nwname;
- char* wname[IXP_MAX_WELEM];
+ uint32_t newfid;
+ uint16_t nwname;
+ char* wname[IXP_MAX_WELEM];
};
struct IxpFRWalk {
- IxpFHdr hdr;
- ushort nwqid;
- IxpQid wqid[IXP_MAX_WELEM];
+ IxpFHdr hdr;
+ uint16_t nwqid;
+ IxpQid wqid[IXP_MAX_WELEM];
};
struct IxpFIO {
- IxpFHdr hdr;
- uvlong offset; /* Tread, Twrite */
- ulong count; /* Tread, Twrite, Rread */
- char* data; /* Twrite, Rread */
+ IxpFHdr hdr;
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
+ char* data; /* Twrite, Rread */
};
struct IxpFRStat {
- IxpFHdr hdr;
- ushort nstat;
- uchar* stat;
+ IxpFHdr hdr;
+ uint16_t nstat;
+ uchar* stat;
};
struct IxpFTWStat {
- IxpFHdr hdr;
- IxpStat stat;
+ IxpFHdr hdr;
+ IxpStat stat;
};
#if defined(IXP_NEEDAPI) && IXP_NEEDAPI <= 89
/* from fcall(3) in plan9port */
typedef struct IxpFcall IxpFcall; /* Deprecated */
struct IxpFcall { /* Deprecated */
- uchar type;
- ushort tag;
- ulong fid;
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
UNION (
STRUCT ( /* Tversion, Rversion */
- ulong msize;
+ uint32_t msize;
char *version;
)
STRUCT ( /* Tflush */
- ushort oldtag;
+ uint16_t oldtag;
)
STRUCT ( /* Rerror */
char *ename;
)
STRUCT ( /* Ropen, Rcreate */
IxpQid qid; /* +Rattach */
- ulong iounit;
+ uint32_t iounit;
)
STRUCT ( /* Rauth */
IxpQid aqid;
)
STRUCT ( /* Tauth, Tattach */
- ulong afid;
+ uint32_t afid;
char *uname;
char *aname;
)
STRUCT ( /* Tcreate */
- ulong perm;
+ uint32_t perm;
char *name;
- uchar mode; /* +Topen */
+ uint8_t mode; /* +Topen */
)
STRUCT ( /* Twalk */
- ulong newfid;
- ushort nwname;
+ uint32_t newfid;
+ uint16_t nwname;
char *wname[IXP_MAX_WELEM];
)
STRUCT ( /* Rwalk */
- ushort nwqid;
+ uint16_t nwqid;
IxpQid wqid[IXP_MAX_WELEM];
)
STRUCT (
- uvlong offset; /* Tread, Twrite */
- ulong count; /* Tread, Twrite, Rread */
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
char *data; /* Twrite, Rread */
)
STRUCT ( /* Rstat */
- ushort nstat;
+ uint16_t nstat;
uchar *stat;
)
STRUCT ( /* Twstat */
@@ -437,7 +440,41 @@ struct IxpFcall { /* Deprecated */
)
};
#else
-typedef union IxpFcall IxpFcall;
+/**
+ * Type: IxpFcall
+ * Type: IxpFType
+ * Type: IxpFAttach
+ * Type: IxpFError
+ * Type: IxpFHdr
+ * Type: IxpFIO
+ * Type: IxpFRAuth
+ * Type: IxpFROpen
+ * Type: IxpFRStat
+ * Type: IxpFRWalk
+ * Type: IxpFTCreate
+ * Type: IxpFTFlush
+ * Type: IxpFTWStat
+ * Type: IxpFTWalk
+ * Type: IxpFVersion
+ *
+ * The IxpFcall structure represents a 9P protocol message. The
+ * P<hdr> element is common to all Fcall types, and may be used to
+ * determine the type and tag of the message. The IxpFcall type is
+ * used heavily in server applications, where it both presents a
+ * request to handler functions and returns a response to the
+ * client.
+ *
+ * Each member of the IxpFcall structure represents a certain
+ * message type, which can be discerned from the P<hdr.type> field.
+ * This value corresponds to one of the IxpFType constants. Types
+ * with significant overlap use the same structures, thus TRead and
+ * RWrite are both represented by IxpFIO and can be accessed via the
+ * P<io> member as well as P<tread> and P<rwrite> respectively.
+ *
+ * See also:
+ * T<Ixp9Srv>, T<Ixp9Req>
+ */
+typedef union IxpFcall IxpFcall;
union IxpFcall {
IxpFHdr hdr;
IxpFVersion version;
@@ -467,11 +504,11 @@ union IxpFcall {
struct IxpConn {
IxpServer* srv;
- void* aux;
- int fd;
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ int fd; /* The file descriptor of the connection. */
void (*read)(IxpConn *);
void (*close)(IxpConn *);
- char closed;
+ char closed; /* Non-zero when P<fd> has been closed. */
/* Private members */
IxpConn *next;
@@ -523,12 +560,12 @@ struct IxpClient {
};
struct IxpCFid {
- uint fid;
+ uint32_t fid;
IxpQid qid;
- uchar mode;
+ uint8_t mode;
uint open;
uint iounit;
- uvlong offset;
+ uint32_t offset;
IxpClient* client;
/* Private members */
@@ -536,13 +573,26 @@ struct IxpCFid {
IxpMutex iolock;
};
+/**
+ * Type: IxpFid
+ *
+ * Represents an open file for a 9P connection. The same
+ * structure persists as long as the file remains open, and is
+ * installed in the T<Ixp9Req> structure for any request Fcall
+ * which references it. Handlers may use the P<aux> member to
+ * store any data which must persist for the life of the open
+ * file.
+ *
+ * See also:
+ * T<Ixp9Req>, T<IxpQid>, T<IxpOMode>
+ */
struct IxpFid {
- char* uid;
- void* aux;
- ulong fid;
- IxpQid qid;
- signed char omode;
- uint iounit;
+ char* uid; /* The uid of the file opener. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ uint32_t fid; /* The ID number of the fid. */
+ IxpQid qid; /* The filesystem-unique QID of the file. */
+ signed char omode; /* The open mode of the file. */
+ uint iounit; /* The maximum size of any IO request. */
/* Private members */
Ixp9Conn* conn;
@@ -551,12 +601,12 @@ struct IxpFid {
struct Ixp9Req {
Ixp9Srv* srv;
- IxpFid* fid;
- IxpFid* newfid;
- Ixp9Req* oldreq;
- IxpFcall ifcall;
- IxpFcall ofcall;
- void* aux;
+ IxpFid* fid; /* Fid structure corresponding to IxpFHdr.fid */
+ IxpFid* newfid; /* Corresponds to IxpFTWStat.newfid */
+ Ixp9Req* oldreq; /* For TFlush requests, the original request. */
+ IxpFcall ifcall; /* The incoming request fcall. */
+ IxpFcall ofcall; /* The response fcall, to be filled by handler. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
/* Private members */
Ixp9Conn *conn;
@@ -564,22 +614,44 @@ struct Ixp9Req {
struct Ixp9Srv {
void* aux;
- void (*attach)(Ixp9Req *r);
- void (*clunk)(Ixp9Req *r);
- void (*create)(Ixp9Req *r);
- void (*flush)(Ixp9Req *r);
- void (*open)(Ixp9Req *r);
- void (*read)(Ixp9Req *r);
- void (*remove)(Ixp9Req *r);
- void (*stat)(Ixp9Req *r);
- void (*walk)(Ixp9Req *r);
- void (*write)(Ixp9Req *r);
- void (*wstat)(Ixp9Req *r);
- void (*freefid)(IxpFid *f);
-};
-
+ void (*attach)(Ixp9Req*);
+ void (*clunk)(Ixp9Req*);
+ void (*create)(Ixp9Req*);
+ void (*flush)(Ixp9Req*);
+ void (*open)(Ixp9Req*);
+ void (*read)(Ixp9Req*);
+ void (*remove)(Ixp9Req*);
+ void (*stat)(Ixp9Req*);
+ void (*walk)(Ixp9Req*);
+ void (*write)(Ixp9Req*);
+ void (*wstat)(Ixp9Req*);
+ void (*freefid)(IxpFid*);
+};
+
+/**
+ * Type: IxpThread
+ * Type: IxpMutex
+ * Type: IxpRWLock
+ * Type: IxpRendez
+ * Variable: ixp_thread
+ *
+ * The IxpThread structure is used to adapt libixp to any of the
+ * myriad threading systems it may be used with. Before any
+ * other of libixp's functions is called, ixp_thread may be set
+ * to a structure filled with implementations of various locking
+ * primitives, along with primitive IO functions which may
+ * perform context switches until data is available.
+ *
+ * The names of the functions should be fairly self-explanitory.
+ * Read/write locks should allow multiple readers and a single
+ * writer of a shared resource, but should not allow new readers
+ * while a writer is waitng for a lock. Mutexes should allow
+ * only one accessor at a time. Rendezvous points are similar to
+ * pthread condition types. P<errbuf> should return a
+ * thread-local buffer or the size IXP_ERRMAX.
+ */
struct IxpThread {
- /* RWLock */
+ /* Read/write lock */
int (*initrwlock)(IxpRWLock*);
void (*rlock)(IxpRWLock*);
int (*canrlock)(IxpRWLock*);
@@ -594,23 +666,23 @@ struct IxpThread {
int (*canlock)(IxpMutex*);
void (*unlock)(IxpMutex*);
void (*mdestroy)(IxpMutex*);
- /* Rendez */
+ /* Rendezvous point */
int (*initrendez)(IxpRendez*);
void (*sleep)(IxpRendez*);
int (*wake)(IxpRendez*);
int (*wakeall)(IxpRendez*);
void (*rdestroy)(IxpRendez*);
/* Other */
- char *(*errbuf)(void);
+ char* (*errbuf)(void);
ssize_t (*read)(int, void*, size_t);
ssize_t (*write)(int, const void*, size_t);
int (*select)(int, fd_set*, fd_set*, fd_set*, struct timeval*);
};
-extern IxpThread *ixp_thread;
-extern int (*ixp_vsnprint)(char*, int, const char*, va_list);
-extern char* (*ixp_vsmprint)(const char*, va_list);
-extern void (*ixp_printfcall)(IxpFcall*);
+extern IxpThread* ixp_thread;
+extern int (*ixp_vsnprint)(char *buf, int nbuf, const char *fmt, va_list);
+extern char* (*ixp_vsmprint)(const char *fmt, va_list);
+extern void (*ixp_printfcall)(IxpFcall*);
/* thread_*.c */
int ixp_taskinit(void);
@@ -624,15 +696,15 @@ int ixp_pthread_init(void);
#endif
/* client.c */
-int ixp_close(IxpCFid*);
-long ixp_pread(IxpCFid*, void*, long, vlong);
-int ixp_print(IxpCFid*, const char*, ...);
-long ixp_pwrite(IxpCFid*, const void*, long, vlong);
-long ixp_read(IxpCFid*, void*, long);
-int ixp_remove(IxpClient*, const char*);
-void ixp_unmount(IxpClient*);
-int ixp_vprint(IxpCFid*, const char*, va_list);
-long ixp_write(IxpCFid*, const void*, long);
+int ixp_close(IxpCFid*);
+long ixp_pread(IxpCFid*, void*, long, int64_t);
+int ixp_print(IxpCFid*, const char*, ...);
+long ixp_pwrite(IxpCFid*, const void*, long, int64_t);
+long ixp_read(IxpCFid*, void*, long);
+int ixp_remove(IxpClient*, const char*);
+void ixp_unmount(IxpClient*);
+int ixp_vprint(IxpCFid*, const char*, va_list);
+long ixp_write(IxpCFid*, const void*, long);
IxpCFid* ixp_create(IxpClient*, const char*, uint perm, uchar mode);
IxpStat* ixp_fstat(IxpCFid*);
IxpClient* ixp_mount(const char*);
@@ -642,15 +714,15 @@ IxpCFid* ixp_open(IxpClient*, const char*, uchar);
IxpStat* ixp_stat(IxpClient*, const char*);
/* convert.c */
-void ixp_pu8(IxpMsg*, uchar*);
-void ixp_pu16(IxpMsg*, ushort*);
-void ixp_pu32(IxpMsg*, ulong*);
-void ixp_pu64(IxpMsg*, uvlong*);
+void ixp_pu8(IxpMsg*, uint8_t*);
+void ixp_pu16(IxpMsg*, uint16_t*);
+void ixp_pu32(IxpMsg*, uint32_t*);
+void ixp_pu64(IxpMsg*, uint64_t*);
void ixp_pdata(IxpMsg*, char**, uint);
void ixp_pstring(IxpMsg*, char**);
-void ixp_pstrings(IxpMsg*, ushort*, char**);
+void ixp_pstrings(IxpMsg*, uint16_t*, char**, uint);
void ixp_pqid(IxpMsg*, IxpQid*);
-void ixp_pqids(IxpMsg*, ushort*, IxpQid*);
+void ixp_pqids(IxpMsg*, uint16_t*, IxpQid*, uint);
void ixp_pstat(IxpMsg*, IxpStat*);
void ixp_pfcall(IxpMsg*, IxpFcall*);
@@ -661,11 +733,16 @@ void ixp_rerrstr(char*, int);
void ixp_werrstr(const char*, ...);
/* request.c */
-void respond(Ixp9Req*, const char *err);
-void serve_9pcon(IxpConn*);
+void ixp_respond(Ixp9Req*, const char *err);
+void ixp_serve9conn(IxpConn*);
+
+#if defined(IXP_NEEDAPI) && IXP_NEEDAPI < 127
+# define respond ixp_respond
+# define serve_9pcon ixp_serve9pconn
+#endif
/* message.c */
-ushort ixp_sizeof_stat(IxpStat*);
+uint16_t ixp_sizeof_stat(IxpStat*);
IxpMsg ixp_message(char*, uint len, uint mode);
void ixp_freestat(IxpStat*);
void ixp_freefcall(IxpFcall*);
diff --git a/include/ixp_local.h b/include/ixp_local.h
@@ -3,6 +3,16 @@
#include <ixp.h>
#include <stdbool.h>
+#undef ulong
+#define ulong _ixpulong
+typedef unsigned long ulong;
+
+#ifdef CPROTO
+# undef bool
+typedef int bool;
+typedef char* va_list;
+#endif
+
char *argv0;
#define ARGBEGIN \
int _argtmp=0, _inargv=0; char *_argv=nil; \
@@ -66,20 +76,20 @@ struct IxpMap {
};
struct IxpTimer {
- Timer* link;
- long msec;
- long id;
- void (*fn)(long, void*);
- void* aux;
+ Timer* link;
+ uint32_t msec;
+ long id;
+ void (*fn)(long, void*);
+ void* aux;
};
/* map.c */
-void ixp_mapfree(Map*, void(*)(void*));
-void ixp_mapexec(Map*, void(*)(void*, void*), void*);
-void ixp_mapinit(Map*, MapEnt**, int);
-bool ixp_mapinsert(Map*, ulong, void*, bool);
-void* ixp_mapget(Map*, ulong);
-void* ixp_maprm(Map*, ulong);
+void ixp_mapfree(IxpMap*, void(*)(void*));
+void ixp_mapexec(IxpMap*, void(*)(void*, void*), void*);
+void ixp_mapinit(IxpMap*, MapEnt**, int);
+bool ixp_mapinsert(IxpMap*, ulong, void*, bool);
+void* ixp_mapget(IxpMap*, ulong);
+void* ixp_maprm(IxpMap*, ulong);
/* mux.c */
void muxfree(IxpClient*);
diff --git a/include/ixp_srvutil.h b/include/ixp_srvutil.h
@@ -9,6 +9,7 @@ typedef struct IxpRequestLink IxpRequestLink;
typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*);
struct IxpPendingLink {
+ /* Private members */
IxpPendingLink* next;
IxpPendingLink* prev;
IxpFid* fid;
@@ -17,12 +18,14 @@ struct IxpPendingLink {
};
struct IxpRequestLink {
+ /* Private members */
IxpRequestLink* next;
IxpRequestLink* prev;
Ixp9Req* req;
};
struct IxpPending {
+ /* Private members */
IxpRequestLink req;
IxpPendingLink fids;
};
@@ -42,7 +45,7 @@ struct IxpFileId {
uint id;
uint index;
IxpDirtab tab;
- ushort nref;
+ uint nref;
uchar volatil;
};
diff --git a/lib/libixp/client.c b/lib/libixp/client.c
@@ -504,7 +504,7 @@ ixp_fstat(IxpCFid *fid) {
}
static long
-_pread(IxpCFid *f, char *buf, long count, vlong offset) {
+_pread(IxpCFid *f, char *buf, long count, int64_t offset) {
Fcall fcall;
int n, len;
@@ -567,7 +567,7 @@ ixp_read(IxpCFid *fid, void *buf, long count) {
}
long
-ixp_pread(IxpCFid *fid, void *buf, long count, vlong offset) {
+ixp_pread(IxpCFid *fid, void *buf, long count, int64_t offset) {
int n;
thread->lock(&fid->iolock);
@@ -577,7 +577,7 @@ ixp_pread(IxpCFid *fid, void *buf, long count, vlong offset) {
}
static long
-_pwrite(IxpCFid *f, const void *buf, long count, vlong offset) {
+_pwrite(IxpCFid *f, const void *buf, long count, int64_t offset) {
Fcall fcall;
int n, len;
@@ -638,7 +638,7 @@ ixp_write(IxpCFid *fid, const void *buf, long count) {
}
long
-ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset) {
+ixp_pwrite(IxpCFid *fid, const void *buf, long count, int64_t offset) {
int n;
thread->lock(&fid->iolock);
@@ -648,8 +648,8 @@ ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset) {
}
/**
- * Function: ixp_vprint
* Function: ixp_print
+ * Function: ixp_vprint
* Variable: ixp_vsmprint
*
* Params:
@@ -666,10 +666,7 @@ ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset) {
* V<ixp_vsmprint> may be set to a function which will
* format its arguments and return a nul-terminated string
* allocated by malloc(3). The default formats its arguments as
- * printf(3). The function must format '%s' as a nul-terminated
- * string and may not consume any arguments not specified by a
- * %-prefixed format specifier, but may otherwise behave in any
- * manner chosen by the user.
+ * printf(3).
*
* Returns:
* These functions return the number of bytes written.
diff --git a/lib/libixp/convert.c b/lib/libixp/convert.c
@@ -14,7 +14,7 @@ enum {
};
static void
-ixp_puint(IxpMsg *msg, uint size, ulong *val) {
+ixp_puint(IxpMsg *msg, uint size, uint32_t *val) {
uchar *pos;
int v;
@@ -51,40 +51,80 @@ ixp_puint(IxpMsg *msg, uint size, ulong *val) {
msg->pos += size;
}
+/**
+ * Function: ixp_pu8
+ * Function: ixp_pu16
+ * Function: ixp_pu32
+ * Function: ixp_pu64
+ *
+ * These functions pack or unpack an unsigned integer of the
+ * specified size.
+ *
+ * If P<msg>->mode is MsgPack, the value pointed to by P<val> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the packed value at P<msg>->pos is loaded into the
+ * location pointed to by P<val>. In both cases, P<msg>->pos is
+ * advanced by the number of bytes read or written. If the call
+ * would advance P<msg>->pos beyond P<msg>->end, P<msg>->pos is
+ * advanced, but nothing is modified.
+ *
+ * See also:
+ * T<IxpMsg>
+ */
void
-ixp_pu32(IxpMsg *msg, ulong *val) {
+ixp_pu32(IxpMsg *msg, uint32_t *val) {
ixp_puint(msg, SDWord, val);
}
void
ixp_pu8(IxpMsg *msg, uchar *val) {
- ulong v;
+ uint32_t v;
v = *val;
ixp_puint(msg, SByte, &v);
*val = (uchar)v;
}
void
-ixp_pu16(IxpMsg *msg, ushort *val) {
- ulong v;
+ixp_pu16(IxpMsg *msg, uint16_t *val) {
+ uint32_t v;
v = *val;
ixp_puint(msg, SWord, &v);
- *val = (ushort)v;
+ *val = (uint16_t)v;
}
void
-ixp_pu64(IxpMsg *msg, uvlong *val) {
- ulong vl, vb;
+ixp_pu64(IxpMsg *msg, uint64_t *val) {
+ uint32_t vl, vb;
vl = (uint)*val;
vb = (uint)(*val>>32);
ixp_puint(msg, SDWord, &vl);
ixp_puint(msg, SDWord, &vb);
- *val = vl | ((uvlong)vb<<32);
+ *val = vl | ((uint64_t)vb<<32);
}
+/**
+ * Function: ixp_pstring
+ *
+ * Packs or unpacks a UTF-8 encoded string. The packed
+ * representation of the string consists of a 16-bit unsigned
+ * integer followed by the contents of the string. The unpacked
+ * representation is a nul-terminated character array.
+ *
+ * If P<msg>->mode is MsgPack, the string pointed to by P<s> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the address pointed to by P<s> is loaded with a
+ * malloc(3) allocated, nul-terminated representation of the
+ * string packed at P<msg>->pos. In either case, P<msg>->pos is
+ * advanced by the number of bytes read or written. If the
+ * action would advance P<msg>->pos beyond P<msg>->end,
+ * P<msg>->pos is still advanced but no other action is taken.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pstrings>, F<ixp_pdata>
+ */
void
ixp_pstring(IxpMsg *msg, char **s) {
- ushort len;
+ uint16_t len;
if(msg->mode == MsgPack)
len = strlen(*s);
@@ -101,14 +141,38 @@ ixp_pstring(IxpMsg *msg, char **s) {
msg->pos += len;
}
+/**
+ * Function: ixp_pstrings
+ *
+ * Packs or unpacks an array of UTF-8 encoded strings. The packed
+ * representation consists of a 16-bit element count followed by
+ * an array of strings as packed by F<ixp_pstring>. The unpacked
+ * representation is an array of nul-terminated character arrays.
+ *
+ * If P<msg>->mode is MsgPack, P<*num> strings in the array
+ * pointed to by P<strings> are packed into the buffer at
+ * P<msg>->pos. If P<msg>->mode is MsgUnpack, P<*num> is loaded
+ * with the number of strings unpacked, the array at
+ * P<*strings> is loaded with pointers to the unpacked strings,
+ * and P<(*strings)[0]> must be freed by the user. In either
+ * case, P<msg>->pos is advanced by the number of bytes read or
+ * written. If the action would advance P<msg>->pos beyond
+ * P<msg>->end, P<msg>->pos is still advanced, but no other
+ * action is taken. If P<*num> is greater than P<max>,
+ * P<msg>->pos is set beyond P<msg>->end and no other action is
+ * taken.
+ *
+ * See also:
+ * P<IxpMsg>, P<ixp_pstring>, P<ixp_pdata>
+ */
void
-ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
+ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings[], uint max) {
char *s;
uint i, size;
- ushort len;
+ uint16_t len;
ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
+ if(*num > max) {
msg->pos = msg->end+1;
return;
}
@@ -145,6 +209,23 @@ ixp_pstrings(IxpMsg *msg, ushort *num, char *strings[]) {
}
}
+/**
+ * Function: ixp_pdata
+ *
+ * Packs or unpacks a raw character buffer of size P<len>.
+ *
+ * If P<msg>->mode is MsgPack, buffer pointed to by P<data> is
+ * packed into the buffer at P<msg>->pos. If P<msg>->mode is
+ * MsgUnpack, the address pointed to by P<s> is loaded with a
+ * malloc(3) allocated buffer with the contents of the buffer at
+ * P<msg>->pos. In either case, P<msg>->pos is advanced by the
+ * number of bytes read or written. If the action would advance
+ * P<msg>->pos beyond P<msg>->end, P<msg>->pos is still advanced
+ * but no other action is taken.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pstring>
+ */
void
ixp_pdata(IxpMsg *msg, char **data, uint len) {
if(msg->pos + len <= msg->end) {
@@ -157,19 +238,40 @@ ixp_pdata(IxpMsg *msg, char **data, uint len) {
msg->pos += len;
}
+/**
+ * Function: ixp_pfcall
+ * Function: ixp_pqid
+ * Function: ixp_pqids
+ * Function: ixp_pstat
+ * Function: ixp_sizeof_stat
+ *
+ * These convenience functions pack or unpack the contents of
+ * libixp structures into their wire format. They behave as if
+ * F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, F<ixp_pu64>, and
+ * F<ixp_pstring> were called for each member of the structure
+ * in question. ixp_pqid is to ixp_pqid as F<ixp_pstrings> is to
+ * ixp_pstring.
+ *
+ * ixp_sizeof_stat returns the size of the packed represention
+ * of P<stat>.
+ *
+ * See also:
+ * T<IxpMsg>, F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>,
+ * F<ixp_pu64>, F<ixp_pstring>, F<ixp_pstrings>
+ */
void
-ixp_pqid(IxpMsg *msg, Qid *qid) {
+ixp_pqid(IxpMsg *msg, IxpQid *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[]) {
+ixp_pqids(IxpMsg *msg, uint16_t *num, IxpQid qid[], uint max) {
int i;
ixp_pu16(msg, num);
- if(*num > IXP_MAX_WELEM) {
+ if(*num > max) {
msg->pos = msg->end+1;
return;
}
@@ -179,8 +281,8 @@ ixp_pqids(IxpMsg *msg, ushort *num, Qid qid[]) {
}
void
-ixp_pstat(IxpMsg *msg, Stat *stat) {
- ushort size;
+ixp_pstat(IxpMsg *msg, IxpStat *stat) {
+ uint16_t size;
if(msg->mode == MsgPack)
size = ixp_sizeof_stat(stat) - 2;
diff --git a/lib/libixp/error.c b/lib/libixp/error.c
@@ -7,8 +7,8 @@
#include "ixp_local.h"
static int
-_vsnprint(char *buf, int n, const char *fmt, va_list ap) {
- return vsnprintf(buf, n, fmt, ap);
+_vsnprint(char *buf, int nbuf, const char *fmt, va_list ap) {
+ return vsnprintf(buf, nbuf, fmt, ap);
}
static char*
@@ -40,10 +40,11 @@ enum {
* Function: ixp_errstr
* Function: ixp_rerrstr
* Function: ixp_werrstr
+ * Variable: ixp_vsnprint
*
* Params:
* buf: The buffer to read and/or fill.
- * size: The size of the buffer.
+ * nbuf: The size of the buffer.
* fmt: A format string with which to write the errstr.
* ...: Arguments to P<fmt>.
*
@@ -56,12 +57,16 @@ enum {
* 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> formats the given
- * format string, P<fmt>, via V<ixp_vsmprint> and writes it to
+ * format string, P<fmt>, via V<ixp_vsnprint> and writes it to
* the error buffer.
*
- * Returns:
- * F<ixp_errbuf> returns the current thread's error
- * string buffer.
+ * V<ixp_vsnprint> may be set to a function which will format
+ * its arguments write the result to the P<nbuf> length buffer
+ * V<buf>. The default value is F<vsnprintf>. The function must
+ * format '%s' as a nul-terminated string and may not consume
+ * any arguments not indicated by a %-prefixed format specifier,
+ * but may otherwise behave in any manner chosen by the user.
+ *
* See also:
* V<ixp_vsmprint>
*/
@@ -78,18 +83,18 @@ ixp_errbuf() {
}
void
-errstr(char *buf, int size) {
+errstr(char *buf, int nbuf) {
char tmp[IXP_ERRMAX];
strncpy(tmp, buf, sizeof tmp);
- rerrstr(buf, size);
+ rerrstr(buf, nbuf);
strncpy(thread->errbuf(), tmp, IXP_ERRMAX);
errno = EPLAN9;
}
void
-rerrstr(char *buf, int size) {
- strncpy(buf, ixp_errbuf(), size);
+rerrstr(char *buf, int nbuf) {
+ strncpy(buf, ixp_errbuf(), nbuf);
}
void
diff --git a/lib/libixp/map.c b/lib/libixp/map.c
@@ -26,7 +26,7 @@ insert(MapEnt **e, ulong val, const char *key) {
}
static MapEnt**
-map_getp(Map *map, ulong val, bool create, bool *exists) {
+map_getp(IxpMap *map, ulong val, bool create, bool *exists) {
MapEnt **e;
e = &map->bucket[val%map->nhash];
@@ -45,7 +45,7 @@ map_getp(Map *map, ulong val, bool create, bool *exists) {
}
void
-ixp_mapfree(Map *map, void (*destroy)(void*)) {
+ixp_mapfree(IxpMap *map, void (*destroy)(void*)) {
int i;
MapEnt *e;
@@ -62,7 +62,7 @@ ixp_mapfree(Map *map, void (*destroy)(void*)) {
}
void
-ixp_mapexec(Map *map, void (*run)(void*, void*), void *context) {
+ixp_mapexec(IxpMap *map, void (*run)(void*, void*), void *context) {
int i;
MapEnt *e;
@@ -74,7 +74,7 @@ ixp_mapexec(Map *map, void (*run)(void*, void*), void *context) {
}
void
-ixp_mapinit(Map *map, MapEnt **buckets, int nbuckets) {
+ixp_mapinit(IxpMap *map, MapEnt **buckets, int nbuckets) {
map->bucket = buckets;
map->nhash = nbuckets;
@@ -83,7 +83,7 @@ ixp_mapinit(Map *map, MapEnt **buckets, int nbuckets) {
}
bool
-ixp_mapinsert(Map *map, ulong key, void *val, bool overwrite) {
+ixp_mapinsert(IxpMap *map, ulong key, void *val, bool overwrite) {
MapEnt *e;
bool existed, res;
@@ -99,7 +99,7 @@ ixp_mapinsert(Map *map, ulong key, void *val, bool overwrite) {
}
void*
-ixp_mapget(Map *map, ulong val) {
+ixp_mapget(IxpMap *map, ulong val) {
MapEnt *e;
void *res;
@@ -111,7 +111,7 @@ ixp_mapget(Map *map, ulong val) {
}
void*
-ixp_maprm(Map *map, ulong val) {
+ixp_maprm(IxpMap *map, ulong val) {
MapEnt **e, *te;
void *ret;
diff --git a/lib/libixp/message.c b/lib/libixp/message.c
@@ -18,6 +18,31 @@ enum {
SQid = SByte + SDWord + SQWord,
};
+/**
+ * Type: IxpMsg
+ * Type: IxpMsgMode
+ * Function: ixp_message
+ *
+ * The IxpMsg struct represents a binary message, and is used
+ * extensively by libixp for converting messages to and from
+ * wire format. The location and size of a buffer are stored in
+ * P<data> and P<size>, respectively. P<pos> points to the
+ * location in the message currently being packed or unpacked,
+ * while P<end> points to the end of the message. The packing
+ * functions advance P<pos> as they go, always ensuring that
+ * they don't read or write past P<end>. When a message is
+ * entirely packed or unpacked, P<pos> whould be less than or
+ * equal to P<end>. Any other state indicates error.
+ *
+ * ixp_message is a convenience function to pack a construct an
+ * IxpMsg from a buffer of a given P<length> and a given
+ * P<mode>. P<pos> and P<data> are set to P<data> and P<end> is
+ * set to P<data> + P<length>.
+ *
+ * See also:
+ * F<ixp_pu8>, F<ixp_pu16>, F<ixp_pu32>, F<ixp_pu64>,
+ * F<ixp_pstring>, F<ixp_pstrings>
+ */
IxpMsg
ixp_message(char *data, uint length, uint mode) {
IxpMsg m;
@@ -30,8 +55,16 @@ ixp_message(char *data, uint length, uint mode) {
return m;
}
+/**
+ * Function: ixp_freestat
+ * Function: ixp_freefcall
+ *
+ * These functions free malloc(3) allocated data in the members
+ * of the passed structures and set those members to nil. They
+ * do not free the structures themselves.
+ */
void
-ixp_freestat(Stat *s) {
+ixp_freestat(IxpStat *s) {
free(s->name);
free(s->uid);
free(s->gid);
@@ -40,7 +73,7 @@ ixp_freestat(Stat *s) {
}
void
-ixp_freefcall(Fcall *fcall) {
+ixp_freefcall(IxpFcall *fcall) {
switch(fcall->hdr.type) {
case RStat:
free(fcall->rstat.stat);
@@ -61,8 +94,8 @@ ixp_freefcall(Fcall *fcall) {
}
}
-ushort
-ixp_sizeof_stat(Stat * stat) {
+uint16_t
+ixp_sizeof_stat(IxpStat *stat) {
return SWord /* size */
+ SWord /* type */
+ SDWord /* dev */
@@ -76,7 +109,7 @@ ixp_sizeof_stat(Stat * stat) {
}
void
-ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
+ixp_pfcall(IxpMsg *msg, IxpFcall *fcall) {
ixp_pu8(msg, &fcall->hdr.type);
ixp_pu16(msg, &fcall->hdr.tag);
@@ -112,10 +145,10 @@ ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
case TWalk:
ixp_pu32(msg, &fcall->hdr.fid);
ixp_pu32(msg, &fcall->twalk.newfid);
- ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname);
+ ixp_pstrings(msg, &fcall->twalk.nwname, fcall->twalk.wname, nelem(fcall->twalk.wname));
break;
case RWalk:
- ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid);
+ ixp_pqids(msg, &fcall->rwalk.nwqid, fcall->rwalk.wqid, nelem(fcall->rwalk.wqid));
break;
case TOpen:
ixp_pu32(msg, &fcall->hdr.fid);
@@ -160,7 +193,7 @@ ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
ixp_pdata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat);
break;
case TWStat: {
- ushort size;
+ uint16_t size;
ixp_pu32(msg, &fcall->hdr.fid);
ixp_pu16(msg, &size);
ixp_pstat(msg, &fcall->twstat.stat);
@@ -169,9 +202,23 @@ ixp_pfcall(IxpMsg *msg, Fcall *fcall) {
}
}
+/**
+ * Function: ixp_fcall2msg
+ * Function: ixp_msg2fcall
+ *
+ * These functions pack or unpack a 9P protocol message. The
+ * message is set to the appropriate mode and its position is
+ * set to the begining of its buffer.
+ *
+ * Returns:
+ * These functions return the size of the message on
+ * success and 0 on failure.
+ * See also:
+ * F<IxpMsg>, F<ixp_pfcall>
+ */
uint
ixp_fcall2msg(IxpMsg *msg, Fcall *fcall) {
- ulong size;
+ uint32_t size;
msg->end = msg->data + msg->size;
msg->pos = msg->data + SDWord;
diff --git a/lib/libixp/request.c b/lib/libixp/request.c
@@ -10,11 +10,18 @@
static void handlereq(Ixp9Req *r);
-static void
-_printfcall(Fcall *f) {
- USED(f);
-}
-void (*ixp_printfcall)(Fcall*) = _printfcall;
+/**
+ * Variable: ixp_printfcall
+ *
+ * When set to a non-null value, ixp_printfcall is called once for
+ * every incoming and outgoing Fcall. It is intended to simplify the
+ * writing of debugging code for clients, but may be used for any
+ * arbitrary purpose.
+ *
+ * See also:
+ * F<ixp_respond>, F<ixp_serve9conn>
+ */
+void (*ixp_printfcall)(Fcall*);
static int
min(int a, int b) {
@@ -79,7 +86,7 @@ decref_p9conn(Ixp9Conn *p9conn) {
static void*
createfid(Map *map, int fid, Ixp9Conn *p9conn) {
- Fid *f;
+ IxpFid *f;
f = emallocz(sizeof *f);
p9conn->ref++;
@@ -95,7 +102,7 @@ createfid(Map *map, int fid, Ixp9Conn *p9conn) {
static int
destroyfid(Ixp9Conn *p9conn, ulong fid) {
- Fid *f;
+ IxpFid *f;
f = ixp_maprm(&p9conn->fidmap, fid);
if(f == nil)
@@ -132,7 +139,7 @@ handlefcall(IxpConn *c) {
p9conn->conn = c;
if(!ixp_mapinsert(&p9conn->tagmap, fcall.hdr.tag, req, false)) {
- respond(req, Eduptag);
+ ixp_respond(req, Eduptag);
return;
}
@@ -153,11 +160,12 @@ handlereq(Ixp9Req *r) {
p9conn = r->conn;
srv = p9conn->srv;
- ixp_printfcall(&r->ifcall);
+ if(ixp_printfcall)
+ ixp_printfcall(&r->ifcall);
switch(r->ifcall.hdr.type) {
default:
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
break;
case TVersion:
if(!strcmp(r->ifcall.version.version, "9P"))
@@ -167,11 +175,11 @@ handlereq(Ixp9Req *r) {
else
r->ofcall.version.version = "unknown";
r->ofcall.version.msize = r->ifcall.version.msize;
- respond(r, nil);
+ ixp_respond(r, nil);
break;
case TAttach:
if(!(r->fid = createfid(&p9conn->fidmap, r->ifcall.hdr.fid, p9conn))) {
- respond(r, Edupfid);
+ ixp_respond(r, Edupfid);
return;
}
/* attach is a required function */
@@ -179,166 +187,166 @@ handlereq(Ixp9Req *r) {
break;
case TClunk:
if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
return;
}
if(!srv->clunk) {
- respond(r, nil);
+ ixp_respond(r, nil);
return;
}
srv->clunk(r);
break;
case TFlush:
if(!(r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag))) {
- respond(r, Enotag);
+ ixp_respond(r, Enotag);
return;
}
if(!srv->flush) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
return;
}
srv->flush(r);
break;
case TCreate:
if(!(r->fid = ixp_mapget(&p9conn->fidmap, r->ifcall.hdr.fid))) {
- respond(r, Enofid);
+ ixp_respond(r, Enofid);
return;
}
if(r->fid->omode != -1) {
- respond(r, Eopen);
+ ixp_respond(r, Eopen);
return;
}
if(!(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
+ ixp_respond(r, Enotdir);
return;
}
if(!p9conn->srv->create) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
if((r->fid->qid.type&QTDIR) && (r->ifcall.topen.mode|P9_ORCLOSE) != (P9_OREAD|P9_ORCLOSE)) {
- respond(r, Eisdir);
+ ixp_respond(r, Eisdir);
return;
}
r->ofcall.ropen.qid = r->fid->qid;
if(!p9conn->srv->open) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
if(r->fid->omode == -1 || r->fid->omode == P9_OWRITE) {
- respond(r, Enoread);
+ ixp_respond(r, Enoread);
return;
}
if(!p9conn->srv->read) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
if(!p9conn->srv->remove) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
if(!p9conn->srv->stat) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
if(r->fid->omode != -1) {
- respond(r, "cannot walk from an open fid");
+ ixp_respond(r, "cannot walk from an open fid");
return;
}
if(r->ifcall.twalk.nwname && !(r->fid->qid.type&QTDIR)) {
- respond(r, Enotdir);
+ ixp_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);
+ ixp_respond(r, Edupfid);
return;
}
}else
r->newfid = r->fid;
if(!p9conn->srv->walk) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_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");
+ ixp_respond(r, "write on fid not opened for writing");
return;
}
if(!p9conn->srv->write) {
- respond(r, Enofunc);
+ ixp_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);
+ ixp_respond(r, Enofid);
return;
}
- if((ushort)~r->ifcall.twstat.stat.type) {
- respond(r, "wstat of type");
+ if(~r->ifcall.twstat.stat.type) {
+ ixp_respond(r, "wstat of type");
return;
}
- if((uint)~r->ifcall.twstat.stat.dev) {
- respond(r, "wstat of dev");
+ if(~r->ifcall.twstat.stat.dev) {
+ ixp_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");
+ if(~r->ifcall.twstat.stat.qid.type || (ulong)~r->ifcall.twstat.stat.qid.version || ~r->ifcall.twstat.stat.qid.path) {
+ ixp_respond(r, "wstat of qid");
return;
}
if(r->ifcall.twstat.stat.muid && r->ifcall.twstat.stat.muid[0]) {
- respond(r, "wstat of muid");
+ ixp_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");
+ if(~r->ifcall.twstat.stat.mode && ((r->ifcall.twstat.stat.mode&DMDIR)>>24) != r->fid->qid.type&QTDIR) {
+ ixp_respond(r, "wstat on DMDIR bit");
return;
}
if(!p9conn->srv->wstat) {
- respond(r, Enofunc);
+ ixp_respond(r, Enofunc);
return;
}
p9conn->srv->wstat(r);
@@ -347,80 +355,93 @@ handlereq(Ixp9Req *r) {
}
}
+/**
+ * Function: ixp_respond
+ *
+ * Sends a response to the given request. The response is
+ * constructed from the P<ofcall> member of the P<req> parameter, or
+ * from the P<error> parameter if it is non-null. In the latter
+ * case, the response is of type RError, while in any other case it
+ * is of the same type as P<req>->P<ofcall>, which must match the
+ * request type in P<req>->P<ifcall>.
+ *
+ * See also:
+ * T<Ixp9Req>, V<ixp_printfcall>
+ */
void
-respond(Ixp9Req *r, const char *error) {
+ixp_respond(Ixp9Req *req, const char *error) {
Ixp9Conn *p9conn;
int msize;
- p9conn = r->conn;
+ p9conn = req->conn;
- switch(r->ifcall.hdr.type) {
+ switch(req->ifcall.hdr.type) {
default:
if(!error)
assert(!"Respond called on unsupported fcall type");
break;
case TVersion:
assert(error == nil);
- free(r->ifcall.version.version);
+ free(req->ifcall.version.version);
thread->lock(&p9conn->rlock);
thread->lock(&p9conn->wlock);
- msize = min(r->ofcall.version.msize, IXP_MAX_MSG);
+ msize = min(req->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;
+ req->ofcall.version.msize = msize;
break;
case TAttach:
if(error)
- destroyfid(p9conn, r->fid->fid);
- free(r->ifcall.tattach.uname);
- free(r->ifcall.tattach.aname);
+ destroyfid(p9conn, req->fid->fid);
+ free(req->ifcall.tattach.uname);
+ free(req->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;
+ req->ofcall.ropen.iounit = p9conn->rmsg.size - 24;
+ req->fid->iounit = req->ofcall.ropen.iounit;
+ req->fid->omode = req->ifcall.topen.mode;
+ req->fid->qid = req->ofcall.ropen.qid;
}
- free(r->ifcall.tcreate.name);
+ free(req->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)
+ if(error || req->ofcall.rwalk.nwqid < req->ifcall.twalk.nwname) {
+ if(req->ifcall.hdr.fid != req->ifcall.twalk.newfid && req->newfid)
+ destroyfid(p9conn, req->newfid->fid);
+ if(!error && req->ofcall.rwalk.nwqid == 0)
error = Enofile;
}else{
- if(r->ofcall.rwalk.nwqid == 0)
- r->newfid->qid = r->fid->qid;
+ if(req->ofcall.rwalk.nwqid == 0)
+ req->newfid->qid = req->fid->qid;
else
- r->newfid->qid = r->ofcall.rwalk.wqid[r->ofcall.rwalk.nwqid-1];
+ req->newfid->qid = req->ofcall.rwalk.wqid[req->ofcall.rwalk.nwqid-1];
}
- free(*r->ifcall.twalk.wname);
+ free(*req->ifcall.twalk.wname);
break;
case TWrite:
- free(r->ifcall.twrite.data);
+ free(req->ifcall.twrite.data);
break;
case TRemove:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
+ if(req->fid)
+ destroyfid(p9conn, req->fid->fid);
break;
case TClunk:
- if(r->fid)
- destroyfid(p9conn, r->fid->fid);
+ if(req->fid)
+ destroyfid(p9conn, req->fid->fid);
break;
case TFlush:
- if((r->oldreq = ixp_mapget(&p9conn->tagmap, r->ifcall.tflush.oldtag)))
- respond(r->oldreq, Eintr);
+ if((req->oldreq = ixp_mapget(&p9conn->tagmap, req->ifcall.tflush.oldtag)))
+ ixp_respond(req->oldreq, Eintr);
break;
case TWStat:
- ixp_freestat(&r->ifcall.twstat.stat);
+ ixp_freestat(&req->ifcall.twstat.stat);
break;
case TRead:
case TStat:
@@ -428,36 +449,37 @@ respond(Ixp9Req *r, const char *error) {
/* Still to be implemented: auth */
}
- r->ofcall.hdr.tag = r->ifcall.hdr.tag;
+ req->ofcall.hdr.tag = req->ifcall.hdr.tag;
if(error == nil)
- r->ofcall.hdr.type = r->ifcall.hdr.type + 1;
+ req->ofcall.hdr.type = req->ifcall.hdr.type + 1;
else {
- r->ofcall.hdr.type = RError;
- r->ofcall.error.ename = (char*)error;
+ req->ofcall.hdr.type = RError;
+ req->ofcall.error.ename = (char*)error;
}
- ixp_printfcall(&r->ofcall);
+ if(ixp_printfcall)
+ ixp_printfcall(&req->ofcall);
- ixp_maprm(&p9conn->tagmap, r->ifcall.hdr.tag);;
+ ixp_maprm(&p9conn->tagmap, req->ifcall.hdr.tag);;
if(p9conn->conn) {
thread->lock(&p9conn->wlock);
- msize = ixp_fcall2msg(&p9conn->wmsg, &r->ofcall);
+ msize = ixp_fcall2msg(&p9conn->wmsg, &req->ofcall);
if(ixp_sendmsg(p9conn->conn->fd, &p9conn->wmsg) != msize)
ixp_hangup(p9conn->conn);
thread->unlock(&p9conn->wlock);
}
- switch(r->ofcall.hdr.type) {
+ switch(req->ofcall.hdr.type) {
case RStat:
- free(r->ofcall.rstat.stat);
+ free(req->ofcall.rstat.stat);
break;
case RRead:
- free(r->ofcall.rread.data);
+ free(req->ofcall.rread.data);
break;
}
- free(r);
+ free(req);
decref_p9conn(p9conn);
}
@@ -481,12 +503,12 @@ voidrequest(void *context, void *arg) {
*(void**)context = flush_req;
}
-/* Clunk an open Fid */
+/* Clunk an open IxpFid */
static void
voidfid(void *context, void *arg) {
Ixp9Conn *p9conn;
Ixp9Req *clunk_req;
- Fid *fid;
+ IxpFid *fid;
fid = arg;
p9conn = fid->conn;
@@ -524,8 +546,33 @@ cleanupconn(IxpConn *c) {
}
/* Handle incoming 9P connections */
+/**
+ * Type: Ixp9Srv
+ * Type: Ixp9Req
+ * Function: ixp_serve9conn
+ *
+ * The ixp_serve9conn handles incoming 9P connections. It is
+ * ordinarily passed as the P<read> member to F<ixp_listen> with an
+ * Ixp9Srv structure passed as the P<aux> member. The handlers
+ * defined in the Ixp9Srv structure are called whenever a matching
+ * Fcall type is received. The handlers are expected to call
+ * F<ixp_respond> at some point, whether before they return or at
+ * some undefined point in the future. Whenever a client
+ * disconnects, libixp generates whatever flush and clunk events are
+ * required to leave the connection in a clean state and waits for
+ * all responses before freeing the connections associated data
+ * structures.
+ *
+ * Whenever a file is closed and an T<IxpFid> is about to be freed,
+ * the P<freefid> member is called to perform any necessary cleanup
+ * and to free any associated resources.
+ *
+ * See also:
+ * F<ixp_listen>, F<ixp_respond>, F<ixp_printfcall>,
+ * F<IxpFcall>, F<IxpFid>
+ */
void
-serve_9pcon(IxpConn *c) {
+ixp_serve9conn(IxpConn *c) {
Ixp9Conn *p9conn;
int fd;
diff --git a/lib/libixp/server.c b/lib/libixp/server.c
@@ -17,19 +17,18 @@
* Params:
* fs: The file descriptor on which to listen.
* aux: A piece of data to store in the connection's
- * S<IxpConn> data structure.
- * read: The function to call when the connection has
+ * P<aux> member of the IxpConn data structure.
+ * read: The function called when the connection has
* data available to read.
- * close: A cleanup function to call when the
+ * close: A cleanup function called when the
* connection is closed.
*
* Starts the server P<srv> listening on P<fd>. The optional
- * callbacks are called as described, with the connections
- * S<IxpConn> data structure as their arguments.
+ * P<read> and P<close> callbacks are called with the IxpConn
+ * structure for the connection as their sole argument.
*
* Returns:
- * Returns the connection's new S<IxpConn> data
- * structure.
+ * Returns the connection's new IxpConn data structure.
*/
IxpConn*
ixp_listen(IxpServer *srv, int fd, void *aux,
diff --git a/lib/libixp/srv_util.c b/lib/libixp/srv_util.c
@@ -1,4 +1,4 @@
-/* Copyright ©2006-2010 Kris Maglione <fbsdaemon at gmail dot com>
+/* Copyright ©2006-2010 Kris Maglione <maglione.k at Gmail>
* See LICENSE file for license details.
*/
#include <assert.h>
@@ -24,14 +24,10 @@ struct IxpQueue {
long len;
};
-/* Macros */
-#define QID(t, i) (((vlong)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
+#define QID(t, i) (((int64_t)((t)&0xFF)<<32)|((i)&0xFFFFFFFF))
-/* Global Vars */
-/***************/
static IxpFileId* free_fileid;
-/* Utility Functions */
/**
* Function: ixp_srv_getfile
* Type: IxpFileId
@@ -104,6 +100,28 @@ ixp_srv_clonefiles(IxpFileId *fileid) {
return r;
}
+/**
+ * Function: ixp_srv_readbuf
+ * Function: ixp_srv_writebuf
+ *
+ * Utility functions for handling TRead and TWrite requests for
+ * files backed by in-memory buffers. For both functions, P<buf>
+ * points to a buffer and P<len> specifies the length of the
+ * buffer. In the case of ixp_srv_writebuf, these values add a
+ * level of pointer indirection, and updates the values if they
+ * change.
+ *
+ * If P<max> has a value other than 0, ixp_srv_writebuf will
+ * truncate any writes to that point in the buffer. Otherwise,
+ * P<*buf> is assumed to be malloc(3) allocated, and is
+ * reallocated to fit the new data as necessary. The buffer is
+ * is always left nul-terminated.
+ *
+ * Bugs:
+ * ixp_srv_writebuf always truncates its buffer to the end
+ * of the most recent write.
+ */
+
void
ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len) {
@@ -176,6 +194,18 @@ ixp_srv_data2cstring(Ixp9Req *req) {
req->ifcall.io.data = p;
}
+/**
+ * Function: ixp_srv_writectl
+ *
+ * This utility function is meant to simplify the writing of
+ * pseudo files to which single-lined commands are written.
+ * In order to use this function, the P<aux> member of
+ * P<req>->fid must be nul or an S<IxpFileId>. Each line of the
+ * written data is stripped of its trailing newline,
+ * nul-terminated, and stored in an S<IxpMsg>. For each line
+ * thus prepared, P<fn> is called with the IxpMsg pointer and
+ * the the P<p> member of the IxpFileId.
+ */
char*
ixp_srv_writectl(Ixp9Req *req, char* (*fn)(void*, IxpMsg*)) {
char *err, *s, *p, c;
@@ -207,6 +237,41 @@ ixp_srv_writectl(Ixp9Req *req, char* (*fn)(void*, IxpMsg*)) {
return err;
}
+/**
+ * Function: ixp_pending_write
+ * Function: ixp_pending_pushfid
+ * Function: ixp_pending_clunk
+ * Function: ixp_pending_flush
+ * Function: ixp_pending_respond
+ * Type: IxpPending
+ *
+ * These functions aid in writing virtual files used for
+ * broadcasting events or writing data when it becomes
+ * available. When a file to be used with these functions is
+ * opened, ixp_pending_pushfid should be called with its
+ * S<IxpFid> as an argument. This sets the IxpFid's P<pending>
+ * member to true. Thereafter, for each file with its
+ * P<pending> member set, ixp_pending_respond should be called
+ * for each TRead request, ixp_pending_clunk for each TClunk
+ * request, and ixp_pending_flush for each TFlush request.
+ *
+ * ixp_pending_write queues the data in P<dat> of length P<ndat>
+ * to be written to each currently pending fid in P<pending>. If
+ * there is a read request pending for a given fid, the data is
+ * written immediately. Otherwise, it is written the next time
+ * ixp_pending_respond is called. Likewise, if there is data
+ * queued when ixp_pending_respond is called, it is written
+ * immediately, otherwise the request is queued.
+ *
+ * The IxpPending data structure is opaque and should be
+ * initialized zeroed before using these functions for the first
+ * time.
+ *
+ * Returns:
+ * ixp_pending_clunk returns true if P<pending> has any
+ * more pending IxpFids.
+ */
+
void
ixp_pending_respond(Ixp9Req *req) {
IxpFileId *file;
@@ -228,7 +293,7 @@ ixp_pending_respond(Ixp9Req *req) {
req_link->prev->next = req_link->next;
free(req_link);
}
- respond(req, nil);
+ ixp_respond(req, nil);
free(queue);
}else {
req_link = emallocz(sizeof *req_link);
@@ -242,13 +307,13 @@ ixp_pending_respond(Ixp9Req *req) {
}
void
-ixp_pending_write(IxpPending *pending, char *dat, long n) {
+ixp_pending_write(IxpPending *pending, char *dat, long ndat) {
IxpRequestLink req_link;
IxpQueue **qp, *queue;
IxpPendingLink *pp;
IxpRequestLink *rp;
- if(n == 0)
+ if(ndat == 0)
return;
if(pending->req.next == nil) {
@@ -262,9 +327,9 @@ ixp_pending_write(IxpPending *pending, char *dat, long n) {
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;
+ queue->dat = emalloc(ndat);
+ memcpy(queue->dat, dat, ndat);
+ queue->len = ndat;
*qp = queue;
}
@@ -348,7 +413,7 @@ ixp_pending_clunk(Ixp9Req *req) {
req_link = req_link->next;
if(r->fid == pend_link->fid) {
pending_flush(r);
- respond(r, "interrupted");
+ ixp_respond(r, "interrupted");
}
}
@@ -362,10 +427,45 @@ ixp_pending_clunk(Ixp9Req *req) {
}
more = (pend_link->pending->fids.next == &pend_link->pending->fids);
free(pend_link);
- respond(req, nil);
+ ixp_respond(req, nil);
return more;
}
+/**
+ * Function: ixp_srv_walkandclone
+ * Function: ixp_srv_readdir
+ * Function: ixp_srv_verifyfile
+ * Type: IxpLookupFn
+ *
+ * These convenience functions simplify the writing of basic and
+ * static file servers. They use a generic file lookup function
+ * to simplify the process of walking, cloning, and returning
+ * directory listings. Given the S<IxpFileId> of a directory and a
+ * filename name should return a new IxpFileId (allocated via
+ * F<ixp_srv_getfile>) for the matching directory entry, or null
+ * if there is no match. If the passed name is null, P<lookup>
+ * should return a linked list of IxpFileIds, one for each child
+ * directory entry.
+ *
+ * ixp_srv_walkandclone handles the moderately complex process
+ * of walking from a directory entry and cloning fids, and calls
+ * F<ixp_respond>. It should be called in response to a TWalk
+ * request.
+ *
+ * ixp_srv_readdir should be called to handle read requests on
+ * directories. It prepares a stat for each child of the
+ * directory, taking into account the requested offset, and
+ * calls F<ixp_respond>. The P<dostat> parameter must be a
+ * function which fills the passed S<IxpStat> pointer based on
+ * the contents of the passed IxpFileId.
+ *
+ * ixp_srv_verifyfile returns whether a file still exists in the
+ * filesystem, and should be used by filesystems that invalidate
+ * files once they have been deleted.
+ *
+ * See also:
+ * S<IxpFileId>, S<ixp_getfile>, S<ixp_freefile>
+ */
bool
ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup) {
IxpFileId *tfile;
@@ -393,7 +493,7 @@ ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(IxpStat*, IxpFi
IxpStat stat;
char *buf;
ulong size, n;
- uvlong offset;
+ uint64_t offset;
file = req->fid->aux;
@@ -424,7 +524,7 @@ ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(IxpStat*, IxpFi
}
req->ofcall.io.count = msg.pos - msg.data;
req->ofcall.io.data = msg.data;
- respond(req, nil);
+ ixp_respond(req, nil);
}
void
@@ -436,8 +536,8 @@ ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup) {
for(i=0; i < req->ifcall.twalk.nwname; i++) {
if(!strcmp(req->ifcall.twalk.wname[i], "..")) {
if(file->next) {
- tfile=file;
- file=file->next;
+ tfile = file;
+ file = file->next;
ixp_srv_freefile(tfile);
}
}else{
@@ -459,7 +559,7 @@ ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup) {
file=file->next;
ixp_srv_freefile(tfile);
}
- respond(req, Enofile);
+ ixp_respond(req, Enofile);
return;
}
/* Remove refs for req->fid if no new fid */
@@ -473,6 +573,6 @@ ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup) {
}else
req->newfid->aux = file;
req->ofcall.rwalk.nwqid = i;
- respond(req, nil);
+ ixp_respond(req, nil);
}
diff --git a/lib/libixp/timer.c b/lib/libixp/timer.c
@@ -51,7 +51,7 @@ long
ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void*), void *aux) {
Timer **tp;
Timer *t;
- long time;
+ uint32_t time;
time = ixp_msec();
if(time == -1)
@@ -105,7 +105,7 @@ ixp_unsettimer(IxpServer *srv, long id) {
return t != nil;
}
-/**
+/*
* Function: ixp_nexttimer
*
* Triggers any timers whose timeouts have ellapsed. This is
@@ -121,7 +121,7 @@ ixp_unsettimer(IxpServer *srv, long id) {
long
ixp_nexttimer(IxpServer *srv) {
Timer *t;
- long time, ret;
+ uint32_t time, ret;
SET(time);
thread->lock(&srv->lk);
diff --git a/lib/libixp/transport.c b/lib/libixp/transport.c
@@ -49,6 +49,27 @@ readn(int fd, IxpMsg *msg, uint count) {
return count - num;
}
+/**
+ * Function: ixp_sendmsg
+ * Function: ixp_recvmsg
+ *
+ * These functions read and write messages to and from the given
+ * file descriptors.
+ *
+ * ixp_sendmsg writes the data at P<msg>->pos upto P<msg>->end.
+ * If the call returns non-zero, all data is assured to have
+ * been written.
+ *
+ * ixp_recvmsg first reads a 32 bit, little-endian length from
+ * P<fd> and then reads a message of that length (including the
+ * 4 byte size specifier) into the buffer at P<msg>->data, so
+ * long as the size is less than P<msg>->size.
+ *
+ * Returns:
+ * These functions return the number of bytes read or
+ * written, or 0 on error. Errors are stored in
+ * F<ixp_errbuf>.
+ */
uint
ixp_sendmsg(int fd, IxpMsg *msg) {
int r;
@@ -70,7 +91,7 @@ ixp_sendmsg(int fd, IxpMsg *msg) {
uint
ixp_recvmsg(int fd, IxpMsg *msg) {
enum { SSize = 4 };
- ulong msize, size;
+ uint32_t msize, size;
msg->mode = MsgUnpack;
msg->pos = msg->data;
diff --git a/lib/libixp/util.c b/lib/libixp/util.c
@@ -11,6 +11,12 @@
#include <pwd.h>
#include "ixp_local.h"
+/**
+ * Function: ixp_smprint
+ *
+ * This function formats its arguments as F<printf> and returns
+ * a F<malloc> allocated string containing the result.
+ */
char*
ixp_smprint(const char *fmt, ...) {
va_list ap;
@@ -125,8 +131,14 @@ ixp_namespace(void) {
return namespace;
}
+/**
+ * Function: ixp_eprint
+ *
+ * libixp calls this function on error. It formats its arguments
+ * as F<printf> and exits the program.
+ */
void
-eprint(const char *fmt, ...) {
+ixp_eprint(const char *fmt, ...) {
va_list ap;
int err;
@@ -170,8 +182,19 @@ mfatal(char *name, uint size) {
exit(1);
}
+/**
+ * Function: ixp_emalloc
+ * Function: ixp_emallocz
+ * Function: ixp_erealloc
+ * Function: ixp_estrdup
+ *
+ * These functions act like their stdlib counterparts, but print
+ * an error message and exit the program if allocation fails.
+ * ixp_emallocz acts like ixp_emalloc but additionally zeros the
+ * result of the allocation.
+ */
void*
-emalloc(uint size) {
+ixp_emalloc(uint size) {
void *ret = malloc(size);
if(!ret)
mfatal("malloc", size);
@@ -179,14 +202,14 @@ emalloc(uint size) {
}
void*
-emallocz(uint size) {
+ixp_emallocz(uint size) {
void *ret = emalloc(size);
memset(ret, 0, size);
return ret;
}
void*
-erealloc(void *ptr, uint size) {
+ixp_erealloc(void *ptr, uint size) {
void *ret = realloc(ptr, size);
if(!ret)
mfatal("realloc", size);
@@ -194,7 +217,7 @@ erealloc(void *ptr, uint size) {
}
char*
-estrdup(const char *str) {
+ixp_estrdup(const char *str) {
void *ret = strdup(str);
if(!ret)
mfatal("strdup", strlen(str));
@@ -202,7 +225,7 @@ estrdup(const char *str) {
}
uint
-tokenize(char *res[], uint reslen, char *str, char delim) {
+ixp_tokenize(char *res[], uint reslen, char *str, char delim) {
char *s;
uint i;
@@ -220,7 +243,7 @@ tokenize(char *res[], uint reslen, char *str, char delim) {
}
uint
-strlcat(char *dst, const char *src, uint size) {
+ixp_strlcat(char *dst, const char *src, uint size) {
const char *s;
char *d;
int n, len;
diff --git a/man/Ixp9Srv.3 b/man/Ixp9Srv.3
@@ -0,0 +1,72 @@
+.TH "IXP9SRV" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+Ixp9Srv, Ixp9Req, ixp_serve9conn
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct Ixp9Srv Ixp9Srv;
+ struct Ixp9Srv {
+ void* aux;
+ void (*attach)(Ixp9Req*);
+ void (*clunk)(Ixp9Req*);
+ void (*create)(Ixp9Req*);
+ void (*flush)(Ixp9Req*);
+ void (*open)(Ixp9Req*);
+ void (*read)(Ixp9Req*);
+ void (*remove)(Ixp9Req*);
+ void (*stat)(Ixp9Req*);
+ void (*walk)(Ixp9Req*);
+ void (*write)(Ixp9Req*);
+ void (*wstat)(Ixp9Req*);
+ void (*freefid)(IxpFid*);
+ }
+
+ typedef struct Ixp9Req Ixp9Req;
+ struct Ixp9Req {
+ Ixp9Srv* srv;
+ IxpFid* fid; /* Fid structure corresponding to IxpFHdr.fid */
+ IxpFid* newfid; /* Corresponds to IxpFTWStat.newfid */
+ Ixp9Req* oldreq; /* For TFlush requests, the original request. */
+ IxpFcall ifcall; /* The incoming request fcall. */
+ IxpFcall ofcall; /* The response fcall, to be filled by handler. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+
+ /* Private members */
+ ...
+ }
+
+ void ixp_serve9conn(IxpConn *c);
+.fi
+
+.SH DESCRIPTION
+.P
+The ixp_serve9conn handles incoming 9P connections. It is
+ordinarily passed as the \fIread\fR member to \fBixp_listen(3)\fR with an
+Ixp9Srv structure passed as the \fIaux\fR member. The handlers
+defined in the Ixp9Srv structure are called whenever a matching
+Fcall type is received. The handlers are expected to call
+\fBixp_respond(3)\fR at some point, whether before they return or at
+some undefined point in the future. Whenever a client
+disconnects, libixp generates whatever flush and clunk events are
+required to leave the connection in a clean state and waits for
+all responses before freeing the connections associated data
+structures.
+
+.P
+Whenever a file is closed and an \fBIxpFid(3)\fR is about to be freed,
+the \fIfreefid\fR member is called to perform any necessary cleanup
+and to free any associated resources.
+
+.SH SEE ALSO
+.P
+ixp_listen(3), ixp_respond(3), ixp_printfcall(3),
+IxpFcall(3), IxpFid(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- Ixp9Srv.man3
+
diff --git a/man/IxpFcall.3 b/man/IxpFcall.3
@@ -0,0 +1,186 @@
+.TH "IXPFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpFcall, IxpFType, IxpFAttach, IxpFError, IxpFHdr, IxpFIO, IxpFRAuth, IxpFROpen, IxpFRStat, IxpFRWalk, IxpFTCreate, IxpFTFlush, IxpFTWStat, IxpFTWalk, IxpFVersion
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpFcall IxpFcall;
+ typedef union IxpFcall IxpFcall;
+ union IxpFcall {
+ IxpFHdr hdr;
+ IxpFVersion version;
+ IxpFVersion tversion;
+ IxpFVersion rversion;
+ IxpFTFlush tflush;
+ IxpFROpen ropen;
+ IxpFROpen rcreate;
+ IxpFROpen rattach;
+ IxpFError error;
+ IxpFRAuth rauth;
+ IxpFAttach tattach;
+ IxpFAttach tauth;
+ IxpFTCreate tcreate;
+ IxpFTCreate topen;
+ IxpFTWalk twalk;
+ IxpFRWalk rwalk;
+ IxpFTWStat twstat;
+ IxpFRStat rstat;
+ IxpFIO twrite;
+ IxpFIO rwrite;
+ IxpFIO tread;
+ IxpFIO rread;
+ IxpFIO io;
+ }
+
+ enum IxpFType {
+ P9_TVersion = 100,
+ P9_RVersion,
+ P9_TAuth = 102,
+ P9_RAuth,
+ P9_TAttach = 104,
+ P9_RAttach,
+ P9_TError = 106, /* illegal */
+ P9_RError,
+ P9_TFlush = 108,
+ P9_RFlush,
+ P9_TWalk = 110,
+ P9_RWalk,
+ P9_TOpen = 112,
+ P9_ROpen,
+ P9_TCreate = 114,
+ P9_RCreate,
+ P9_TRead = 116,
+ P9_RRead,
+ P9_TWrite = 118,
+ P9_RWrite,
+ P9_TClunk = 120,
+ P9_RClunk,
+ P9_TRemove = 122,
+ P9_RRemove,
+ P9_TStat = 124,
+ P9_RStat,
+ P9_TWStat = 126,
+ P9_RWStat,
+ }
+
+ typedef struct IxpFAttach IxpFAttach;
+ struct IxpFAttach {
+ IxpFHdr hdr;
+ uint32_t afid;
+ char* uname;
+ char* aname;
+ }
+
+ typedef struct IxpFError IxpFError;
+ struct IxpFError {
+ IxpFHdr hdr;
+ char* ename;
+ }
+
+ typedef struct IxpFHdr IxpFHdr;
+ struct IxpFHdr {
+ uint8_t type;
+ uint16_t tag;
+ uint32_t fid;
+ }
+
+ typedef struct IxpFIO IxpFIO;
+ struct IxpFIO {
+ IxpFHdr hdr;
+ uint64_t offset; /* Tread, Twrite */
+ uint32_t count; /* Tread, Twrite, Rread */
+ char* data; /* Twrite, Rread */
+ }
+
+ typedef struct IxpFRAuth IxpFRAuth;
+ struct IxpFRAuth {
+ IxpFHdr hdr;
+ IxpQid aqid;
+ }
+
+ typedef struct IxpFROpen IxpFROpen;
+ struct IxpFROpen {
+ IxpFHdr hdr;
+ IxpQid qid; /* +Rattach */
+ uint32_t iounit;
+ }
+
+ typedef struct IxpFRStat IxpFRStat;
+ struct IxpFRStat {
+ IxpFHdr hdr;
+ uint16_t nstat;
+ uchar* stat;
+ }
+
+ typedef struct IxpFRWalk IxpFRWalk;
+ struct IxpFRWalk {
+ IxpFHdr hdr;
+ uint16_t nwqid;
+ IxpQid wqid\fI[IXP_MAX_WELEM]\fR;
+ }
+
+ typedef struct IxpFTCreate IxpFTCreate;
+ struct IxpFTCreate {
+ IxpFHdr hdr;
+ uint32_t perm;
+ char* name;
+ uint8_t mode; /* +Topen */
+ }
+
+ typedef struct IxpFTFlush IxpFTFlush;
+ struct IxpFTFlush {
+ IxpFHdr hdr;
+ uint16_t oldtag;
+ }
+
+ typedef struct IxpFTWStat IxpFTWStat;
+ struct IxpFTWStat {
+ IxpFHdr hdr;
+ IxpStat stat;
+ }
+
+ typedef struct IxpFTWalk IxpFTWalk;
+ struct IxpFTWalk {
+ IxpFHdr hdr;
+ uint32_t newfid;
+ uint16_t nwname;
+ char* wname\fI[IXP_MAX_WELEM]\fR;
+ }
+
+ typedef struct IxpFVersion IxpFVersion;
+ struct IxpFVersion {
+ IxpFHdr hdr;
+ uint32_t msize;
+ char* version;
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpFcall structure represents a 9P protocol message. The
+\fIhdr\fR element is common to all Fcall types, and may be used to
+determine the type and tag of the message. The IxpFcall type is
+used heavily in server applications, where it both presents a
+request to handler functions and returns a response to the
+client.
+
+.P
+Each member of the IxpFcall structure represents a certain
+message type, which can be discerned from the \fIhdr.type\fR field.
+This value corresponds to one of the IxpFType constants. Types
+with significant overlap use the same structures, thus TRead and
+RWrite are both represented by IxpFIO and can be accessed via the
+\fIio\fR member as well as \fItread\fR and \fIrwrite\fR respectively.
+
+.SH SEE ALSO
+.P
+Ixp9Srv(3), Ixp9Req(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpFcall.man3
+
diff --git a/man/IxpFid.3 b/man/IxpFid.3
@@ -0,0 +1,41 @@
+.TH "IXPFID" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpFid
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpFid IxpFid;
+ struct IxpFid {
+ char* uid; /* The uid of the file opener. */
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ uint32_t fid; /* The ID number of the fid. */
+ IxpQid qid; /* The filesystem-unique QID of the file. */
+ signed char omode; /* The open mode of the file. */
+ uint iounit; /* The maximum size of any IO request. */
+
+ /* Private members */
+ ...
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+Represents an open file for a 9P connection. The same
+structure persists as long as the file remains open, and is
+installed in the \fBIxp9Req(3)\fR structure for any request Fcall
+which references it. Handlers may use the \fIaux\fR member to
+store any data which must persist for the life of the open
+file.
+
+.SH SEE ALSO
+.P
+Ixp9Req(3), IxpQid(3), IxpOMode(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpFid.man3
+
diff --git a/man/IxpMsg.3 b/man/IxpMsg.3
@@ -0,0 +1,55 @@
+.TH "IXPMSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpMsg, IxpMsgMode, ixp_message
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpMsg IxpMsg;
+ struct IxpMsg {
+ char* data; /* Begining of buffer. */
+ char* pos; /* Current position in buffer. */
+ char* end; /* End of message. */
+ uint size; /* Size of buffer. */
+ uint mode; /* MsgPack or MsgUnpack. */
+ }
+
+ enum IxpMsgMode {
+ MsgPack,
+ MsgUnpack,
+ }
+
+ IxpMsg ixp_message(char *data, uint length, uint mode);
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpMsg struct represents a binary message, and is used
+extensively by libixp for converting messages to and from
+wire format. The location and size of a buffer are stored in
+\fIdata\fR and \fIsize\fR, respectively. \fIpos\fR points to the
+location in the message currently being packed or unpacked,
+while \fIend\fR points to the end of the message. The packing
+functions advance \fIpos\fR as they go, always ensuring that
+they don't read or write past \fIend\fR. When a message is
+entirely packed or unpacked, \fIpos\fR whould be less than or
+equal to \fIend\fR. Any other state indicates error.
+
+.P
+ixp_message is a convenience function to pack a construct an
+IxpMsg from a buffer of a given \fIlength\fR and a given
+\fImode\fR. \fIpos\fR and \fIdata\fR are set to \fIdata\fR and \fIend\fR is
+set to \fIdata\fR + \fIlength\fR.
+
+.SH SEE ALSO
+.P
+ixp_pu8(3), ixp_pu16(3), ixp_pu32(3), ixp_pu64(3),
+ixp_pstring(3), ixp_pstrings(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpMsg.man3
+
diff --git a/man/IxpThread.3 b/man/IxpThread.3
@@ -0,0 +1,81 @@
+.TH "IXPTHREAD" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+IxpThread, IxpMutex, IxpRWLock, IxpRendez, ixp_thread
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ typedef struct IxpThread IxpThread;
+ struct IxpThread {
+ /* Read/write lock */
+ int (*initrwlock)(IxpRWLock*);
+ void (*rlock)(IxpRWLock*);
+ int (*canrlock)(IxpRWLock*);
+ void (*runlock)(IxpRWLock*);
+ void (*wlock)(IxpRWLock*);
+ int (*canwlock)(IxpRWLock*);
+ void (*wunlock)(IxpRWLock*);
+ void (*rwdestroy)(IxpRWLock*);
+ /* Mutex */
+ int (*initmutex)(IxpMutex*);
+ void (*lock)(IxpMutex*);
+ int (*canlock)(IxpMutex*);
+ void (*unlock)(IxpMutex*);
+ void (*mdestroy)(IxpMutex*);
+ /* Rendezvous point */
+ int (*initrendez)(IxpRendez*);
+ void (*sleep)(IxpRendez*);
+ int (*wake)(IxpRendez*);
+ int (*wakeall)(IxpRendez*);
+ void (*rdestroy)(IxpRendez*);
+ /* Other */
+ char* (*errbuf)(void);
+ ssize_t (*read)(int, void*, size_t);
+ ssize_t (*write)(int, const void*, size_t);
+ int (*select)(int, fd_set*, fd_set*, fd_set*, struct timeval*);
+ }
+
+ typedef struct IxpMutex IxpMutex;
+ struct IxpMutex {
+ void* aux;
+ }
+
+ typedef struct IxpRWLock IxpRWLock;
+ struct IxpRWLock {
+ void* aux;
+ }
+
+ typedef struct IxpRendez IxpRendez;
+ struct IxpRendez {
+ IxpMutex* mutex;
+ void* aux;
+ }
+
+ IxpThread* ixp_thread;
+.fi
+
+.SH DESCRIPTION
+.P
+The IxpThread structure is used to adapt libixp to any of the
+myriad threading systems it may be used with. Before any
+other of libixp's functions is called, ixp_thread may be set
+to a structure filled with implementations of various locking
+primitives, along with primitive IO functions which may
+perform context switches until data is available.
+
+.P
+The names of the functions should be fairly self\-explanitory.
+Read/write locks should allow multiple readers and a single
+writer of a shared resource, but should not allow new readers
+while a writer is waitng for a lock. Mutexes should allow
+only one accessor at a time. Rendezvous points are similar to
+pthread condition types. \fIerrbuf\fR should return a
+thread\-local buffer or the size IXP_ERRMAX.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- IxpThread.man3
+
diff --git a/man/ixp_close.3 b/man/ixp_close.3
@@ -6,6 +6,8 @@ ixp_close
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
int ixp_close(IxpCFid *f);
.fi
diff --git a/man/ixp_dial.3 b/man/ixp_dial.3
@@ -6,6 +6,8 @@ ixp_dial, ixp_announce
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
int ixp_dial(const char *address);
int ixp_announce(const char *address);
diff --git a/man/ixp_emalloc.3 b/man/ixp_emalloc.3
@@ -0,0 +1,30 @@
+.TH "IXP_EMALLOC" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_emalloc, ixp_emallocz, ixp_erealloc, ixp_estrdup
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void *ixp_emalloc(uint size);
+
+ void *ixp_emallocz(uint size);
+
+ void *ixp_erealloc(void *ptr, uint size);
+
+ char *ixp_estrdup(const char *str);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions act like their stdlib counterparts, but print
+an error message and exit the program if allocation fails.
+ixp_emallocz acts like ixp_emalloc but additionally zeros the
+result of the allocation.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_emalloc.man3
+
diff --git a/man/ixp_eprint.3 b/man/ixp_eprint.3
@@ -0,0 +1,22 @@
+.TH "IXP_EPRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_eprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_eprint(const char *fmt, ...);
+.fi
+
+.SH DESCRIPTION
+.P
+libixp calls this function on error. It formats its arguments
+as \fBprintf(3)\fR and exits the program.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_eprint.man3
+
diff --git a/man/ixp_errbuf.3 b/man/ixp_errbuf.3
@@ -2,17 +2,21 @@
.SH NAME
.P
-ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr
+ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr, ixp_vsnprint
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
char *ixp_errbuf(void);
- void ixp_errstr(char *buf, int size);
+ void ixp_errstr(char *buf, int nbuf);
- void ixp_rerrstr(char *buf, int size);
+ void ixp_rerrstr(char *buf, int nbuf);
void ixp_werrstr(const char *fmt, ...);
+
+ int (*ixp_vsnprint)(char *buf, int nbuf, const char *fmt, va_list);
.fi
.SH PARAMETERS
@@ -20,7 +24,7 @@ ixp_errbuf, ixp_errstr, ixp_rerrstr, ixp_werrstr
buf
The buffer to read and/or fill.
.TP
-size
+nbuf
The size of the buffer.
.TP
fmt
@@ -41,13 +45,16 @@ thread. \fBixp_rerrstr(3)\fR fills \fIbuf\fR with the data from
the current thread's error buffer, while \fBixp_errstr(3)\fR
exchanges \fIbuf\fR's contents with those of the current
thread's error buffer. \fBixp_werrstr(3)\fR formats the given
-format string, \fIfmt\fR, via \fBixp_vsmprint(3)\fR and writes it to
+format string, \fIfmt\fR, via \fBixp_vsnprint(3)\fR and writes it to
the error buffer.
-.SH RETURN VALUE
.P
-\fBixp_errbuf(3)\fR returns the current thread's error
-string buffer.
+\fBixp_vsnprint(3)\fR may be set to a function which will format
+its arguments write the result to the \fInbuf\fR length buffer
+\fBbuf(3)\fR. The default value is \fBvsnprintf(3)\fR. The function must
+format '%s' as a nul\-terminated string and may not consume
+any arguments not indicated by a %\-prefixed format specifier,
+but may otherwise behave in any manner chosen by the user.
.SH SEE ALSO
.P
diff --git a/man/ixp_fcall2msg.3 b/man/ixp_fcall2msg.3
@@ -0,0 +1,34 @@
+.TH "IXP_FCALL2MSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_fcall2msg, ixp_msg2fcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ uint ixp_fcall2msg(IxpMsg *msg, Fcall *fcall);
+
+ uint ixp_msg2fcall(IxpMsg *msg, Fcall *fcall);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions pack or unpack a 9P protocol message. The
+message is set to the appropriate mode and its position is
+set to the begining of its buffer.
+
+.SH RETURN VALUE
+.P
+These functions return the size of the message on
+success and 0 on failure.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pfcall(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_fcall2msg.man3
+
diff --git a/man/ixp_freestat.3 b/man/ixp_freestat.3
@@ -0,0 +1,25 @@
+.TH "IXP_FREESTAT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_freestat, ixp_freefcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_freestat(Stat *s);
+
+ void ixp_freefcall(Fcall *fcall);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions free malloc(3) allocated data in the members
+of the passed structures and set those members to nil. They
+do not free the structures themselves.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_freestat.man3
+
diff --git a/man/ixp_hangup.3 b/man/ixp_hangup.3
@@ -6,6 +6,8 @@ ixp_hangup, ixp_server_close
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
void ixp_hangup(IxpConn *c);
void ixp_server_close(IxpServer *s);
diff --git a/man/ixp_listen.3 b/man/ixp_listen.3
@@ -6,16 +6,18 @@ ixp_listen, IxpConn
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
IxpConn *ixp_listen(IxpServer *srv, int fd, void *aux, void (*read)(IxpConn *), void (*close)(IxpConn *));
typedef struct IxpConn IxpConn;
struct IxpConn {
IxpServer* srv;
- void* aux;
- int fd;
+ void* aux; /* Arbitrary pointer, to be used by handlers. */
+ int fd; /* The file descriptor of the connection. */
void (*read)(IxpConn *);
void (*close)(IxpConn *);
- char closed;
+ char closed; /* Non-zero when //fd// has been closed. */
/* Private members */
...
@@ -29,26 +31,25 @@ The file descriptor on which to listen.
.TP
aux
A piece of data to store in the connection's
-\fBIxpConn(3)\fR data structure.
+\fIaux\fR member of the IxpConn data structure.
.TP
read
-The function to call when the connection has
+The function called when the connection has
data available to read.
.TP
close
-A cleanup function to call when the
+A cleanup function called when the
connection is closed.
.SH DESCRIPTION
.P
Starts the server \fIsrv\fR listening on \fIfd\fR. The optional
-callbacks are called as described, with the connections
-\fBIxpConn(3)\fR data structure as their arguments.
+\fIread\fR and \fIclose\fR callbacks are called with the IxpConn
+structure for the connection as their sole argument.
.SH RETURN VALUE
.P
-Returns the connection's new \fBIxpConn(3)\fR data
-structure.
+Returns the connection's new IxpConn data structure.
.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
diff --git a/man/ixp_mount.3 b/man/ixp_mount.3
@@ -6,6 +6,8 @@ ixp_mount, ixp_mountfd, ixp_nsmount, IxpClient
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
IxpClient *ixp_mount(const char *address);
IxpClient *ixp_mountfd(int fd);
diff --git a/man/ixp_msec.3 b/man/ixp_msec.3
@@ -6,6 +6,8 @@ ixp_msec
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
long ixp_msec(void);
.fi
diff --git a/man/ixp_namespace.3 b/man/ixp_namespace.3
@@ -6,6 +6,8 @@ ixp_namespace
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
char *ixp_namespace(void);
.fi
diff --git a/man/ixp_nexttimer.3 b/man/ixp_nexttimer.3
@@ -1,30 +0,0 @@
-.TH "IXP_NEXTTIMER" 3 "2010 Jun" "libixp Manual"
-
-.SH NAME
-.P
-ixp_nexttimer
-
-.SH SYNOPSIS
-.nf
- long ixp_nexttimer(IxpServer *srv);
-.fi
-
-.SH DESCRIPTION
-.P
-Triggers any timers whose timeouts have ellapsed. This is
-primarily intended to be called from libixp's select
-loop.
-
-.SH RETURN VALUE
-.P
-Returns the number of milliseconds until the next
-timer's timeout.
-
-.SH SEE ALSO
-.P
-ixp_settimer(3), ixp_serverloop(3)
-
-
-.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
-.\" cmdline: txt2tags -o- ixp_nexttimer.man3
-
diff --git a/man/ixp_open.3 b/man/ixp_open.3
@@ -6,18 +6,20 @@ ixp_open, ixp_create, IxpCFid, IxpOMode
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
IxpCFid *ixp_open(IxpClient *c, const char *path, uchar mode);
IxpCFid *ixp_create(IxpClient *c, const char *path, uint perm, uchar mode);
typedef struct IxpCFid IxpCFid;
struct IxpCFid {
- uint fid;
+ uint32_t fid;
IxpQid qid;
- uchar mode;
+ uint8_t mode;
uint open;
uint iounit;
- uvlong offset;
+ uint32_t offset;
IxpClient* client;
/* Private members */
diff --git a/man/ixp_pdata.3 b/man/ixp_pdata.3
@@ -0,0 +1,35 @@
+.TH "IXP_PDATA" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pdata
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pdata(IxpMsg *msg, char **data, uint len);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks a raw character buffer of size \fIlen\fR.
+
+.P
+If \fImsg\fR\->mode is MsgPack, buffer pointed to by \fIdata\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the address pointed to by \fIs\fR is loaded with a
+malloc(3) allocated buffer with the contents of the buffer at
+\fImsg\fR\->pos. In either case, \fImsg\fR\->pos is advanced by the
+number of bytes read or written. If the action would advance
+\fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is still advanced
+but no other action is taken.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pstring(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pdata.man3
+
diff --git a/man/ixp_pending_write.3 b/man/ixp_pending_write.3
@@ -0,0 +1,62 @@
+.TH "IXP_PENDING_WRITE" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pending_write, ixp_pending_pushfid, ixp_pending_clunk, ixp_pending_flush, ixp_pending_respond, IxpPending
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_pending_write(IxpPending *pending, char *dat, long ndat);
+
+ void ixp_pending_pushfid(IxpPending *pending, Fid *fid);
+
+ bool ixp_pending_clunk(Ixp9Req *req);
+
+ void ixp_pending_flush(Ixp9Req *req);
+
+ void ixp_pending_respond(Ixp9Req *req);
+
+ typedef struct IxpPending IxpPending;
+ struct IxpPending {
+ /* Private members */
+ ...
+ }
+.fi
+
+.SH DESCRIPTION
+.P
+These functions aid in writing virtual files used for
+broadcasting events or writing data when it becomes
+available. When a file to be used with these functions is
+opened, ixp_pending_pushfid should be called with its
+\fBIxpFid(3)\fR as an argument. This sets the IxpFid's \fIpending\fR
+member to true. Thereafter, for each file with its
+\fIpending\fR member set, ixp_pending_respond should be called
+for each TRead request, ixp_pending_clunk for each TClunk
+request, and ixp_pending_flush for each TFlush request.
+
+.P
+ixp_pending_write queues the data in \fIdat\fR of length \fIndat\fR
+to be written to each currently pending fid in \fIpending\fR. If
+there is a read request pending for a given fid, the data is
+written immediately. Otherwise, it is written the next time
+ixp_pending_respond is called. Likewise, if there is data
+queued when ixp_pending_respond is called, it is written
+immediately, otherwise the request is queued.
+
+.P
+The IxpPending data structure is opaque and should be
+initialized zeroed before using these functions for the first
+time.
+
+.SH RETURN VALUE
+.P
+ixp_pending_clunk returns true if \fIpending\fR has any
+more pending IxpFids.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pending_write.man3
+
diff --git a/man/ixp_pfcall.3 b/man/ixp_pfcall.3
@@ -0,0 +1,43 @@
+.TH "IXP_PFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pfcall, ixp_pqid, ixp_pqids, ixp_pstat, ixp_sizeof_stat
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pfcall(IxpMsg *msg, Fcall *fcall);
+
+ void ixp_pqid(IxpMsg *msg, Qid *qid);
+
+ void ixp_pqids(IxpMsg *msg, uint16_t *num, Qid qid\fI[]\fR, uint max);
+
+ void ixp_pstat(IxpMsg *msg, Stat *stat);
+
+ uint16_t ixp_sizeof_stat(Stat *stat);
+.fi
+
+.SH DESCRIPTION
+.P
+These convenience functions pack or unpack the contents of
+libixp structures into their wire format. They behave as if
+\fBixp_pu8(3)\fR, \fBixp_pu16(3)\fR, \fBixp_pu32(3)\fR, \fBixp_pu64(3)\fR, and
+\fBixp_pstring(3)\fR were called for each member of the structure
+in question. ixp_pqid is to ixp_pqid as \fBixp_pstrings(3)\fR is to
+ixp_pstring.
+
+.P
+ixp_sizeof_stat returns the size of the packed represention
+of \fIstat\fR.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pu8(3), ixp_pu16(3), ixp_pu32(3),
+ixp_pu64(3), ixp_pstring(3), ixp_pstrings(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pfcall.man3
+
diff --git a/man/ixp_print.3 b/man/ixp_print.3
@@ -0,0 +1,57 @@
+.TH "IXP_PRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_print, ixp_vprint, ixp_vsmprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ int ixp_print(IxpCFid *fid, const char *fmt, ...);
+
+ int ixp_vprint(IxpCFid *fid, const char *fmt, va_list args);
+
+ char* (*ixp_vsmprint)(const char *fmt, va_list);
+.fi
+
+.SH PARAMETERS
+.TP
+fid
+An open IxpCFid to which to write the result.
+.TP
+fmt
+The string with which to format the data.
+.TP
+args
+A va_list holding the arguments to the format
+string.
+.TP
+.RB ...
+The arguments to the format string.
+
+.SH DESCRIPTION
+.P
+These functions act like the standard formatted IO
+functions. They write the result of the formatting to the
+file pointed to by C<fid>.
+
+.P
+\fBixp_vsmprint(3)\fR may be set to a function which will
+format its arguments and return a nul\-terminated string
+allocated by malloc(3). The default formats its arguments as
+printf(3).
+
+.SH RETURN VALUE
+.P
+These functions return the number of bytes written.
+There is currently no way to detect failure.
+
+.SH SEE ALSO
+.P
+ixp_mount(3), ixp_open(3), printf(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_print.man3
+
diff --git a/man/ixp_printfcall.3 b/man/ixp_printfcall.3
@@ -0,0 +1,28 @@
+.TH "IXP_PRINTFCALL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_printfcall
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void (*ixp_printfcall)(IxpFcall*);
+.fi
+
+.SH DESCRIPTION
+.P
+When set to a non\-null value, ixp_printfcall is called once for
+every incoming and outgoing Fcall. It is intended to simplify the
+writing of debugging code for clients, but may be used for any
+arbitrary purpose.
+
+.SH SEE ALSO
+.P
+ixp_respond(3), ixp_serve9conn(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_printfcall.man3
+
diff --git a/man/ixp_pstring.3 b/man/ixp_pstring.3
@@ -0,0 +1,38 @@
+.TH "IXP_PSTRING" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pstring
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pstring(IxpMsg *msg, char **s);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks a UTF\-8 encoded string. The packed
+representation of the string consists of a 16\-bit unsigned
+integer followed by the contents of the string. The unpacked
+representation is a nul\-terminated character array.
+
+.P
+If \fImsg\fR\->mode is MsgPack, the string pointed to by \fIs\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the address pointed to by \fIs\fR is loaded with a
+malloc(3) allocated, nul\-terminated representation of the
+string packed at \fImsg\fR\->pos. In either case, \fImsg\fR\->pos is
+advanced by the number of bytes read or written. If the
+action would advance \fImsg\fR\->pos beyond \fImsg\fR\->end,
+\fImsg\fR\->pos is still advanced but no other action is taken.
+
+.SH SEE ALSO
+.P
+IxpMsg(3), ixp_pstrings(3), ixp_pdata(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pstring.man3
+
diff --git a/man/ixp_pstrings.3 b/man/ixp_pstrings.3
@@ -0,0 +1,42 @@
+.TH "IXP_PSTRINGS" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pstrings
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pstrings(IxpMsg *msg, uint16_t *num, char *strings\fI[]\fR, uint max);
+.fi
+
+.SH DESCRIPTION
+.P
+Packs or unpacks an array of UTF\-8 encoded strings. The packed
+representation consists of a 16\-bit element count followed by
+an array of strings as packed by \fBixp_pstring(3)\fR. The unpacked
+representation is an array of nul\-terminated character arrays.
+
+.P
+If \fImsg\fR\->mode is MsgPack, \fI*num\fR strings in the array
+pointed to by \fIstrings\fR are packed into the buffer at
+\fImsg\fR\->pos. If \fImsg\fR\->mode is MsgUnpack, \fI*num\fR is loaded
+with the number of strings unpacked, the array at
+\fI*strings\fR is loaded with pointers to the unpacked strings,
+and \fI(*strings)\fI[0]\fR\fR must be freed by the user. In either
+case, \fImsg\fR\->pos is advanced by the number of bytes read or
+written. If the action would advance \fImsg\fR\->pos beyond
+\fImsg\fR\->end, \fImsg\fR\->pos is still advanced, but no other
+action is taken. If \fI*num\fR is greater than \fImax\fR,
+\fImsg\fR\->pos is set beyond \fImsg\fR\->end and no other action is
+taken.
+
+.SH SEE ALSO
+.P
+\fIIxpMsg\fR, \fIixp_pstring\fR, \fIixp_pdata\fR
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pstrings.man3
+
diff --git a/man/ixp_pu8.3 b/man/ixp_pu8.3
@@ -0,0 +1,41 @@
+.TH "IXP_PU8" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_pu8, ixp_pu16, ixp_pu32, ixp_pu64
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_pu8(IxpMsg *msg, uchar *val);
+
+ void ixp_pu16(IxpMsg *msg, uint16_t *val);
+
+ void ixp_pu32(IxpMsg *msg, uint32_t *val);
+
+ void ixp_pu64(IxpMsg *msg, uint64_t *val);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions pack or unpack an unsigned integer of the
+specified size.
+
+.P
+If \fImsg\fR\->mode is MsgPack, the value pointed to by \fIval\fR is
+packed into the buffer at \fImsg\fR\->pos. If \fImsg\fR\->mode is
+MsgUnpack, the packed value at \fImsg\fR\->pos is loaded into the
+location pointed to by \fIval\fR. In both cases, \fImsg\fR\->pos is
+advanced by the number of bytes read or written. If the call
+would advance \fImsg\fR\->pos beyond \fImsg\fR\->end, \fImsg\fR\->pos is
+advanced, but nothing is modified.
+
+.SH SEE ALSO
+.P
+IxpMsg(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_pu8.man3
+
diff --git a/man/ixp_read.3 b/man/ixp_read.3
@@ -6,9 +6,11 @@ ixp_read, ixp_pread
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
long ixp_read(IxpCFid *fid, void *buf, long count);
- long ixp_pread(IxpCFid *fid, void *buf, long count, vlong offset);
+ long ixp_pread(IxpCFid *fid, void *buf, long count, int64_t offset);
.fi
.SH PARAMETERS
diff --git a/man/ixp_remove.3 b/man/ixp_remove.3
@@ -6,6 +6,8 @@ ixp_remove
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
int ixp_remove(IxpClient *c, const char *path);
.fi
diff --git a/man/ixp_respond.3 b/man/ixp_respond.3
@@ -0,0 +1,30 @@
+.TH "IXP_RESPOND" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_respond
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ void ixp_respond(Ixp9Req *req, const char *error);
+.fi
+
+.SH DESCRIPTION
+.P
+Sends a response to the given request. The response is
+constructed from the \fIofcall\fR member of the \fIreq\fR parameter, or
+from the \fIerror\fR parameter if it is non\-null. In the latter
+case, the response is of type RError, while in any other case it
+is of the same type as \fIreq\fR\->\fIofcall\fR, which must match the
+request type in \fIreq\fR\->\fIifcall\fR.
+
+.SH SEE ALSO
+.P
+Ixp9Req(3), ixp_printfcall(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_respond.man3
+
diff --git a/man/ixp_sendmsg.3 b/man/ixp_sendmsg.3
@@ -0,0 +1,41 @@
+.TH "IXP_SENDMSG" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_sendmsg, ixp_recvmsg
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ uint ixp_sendmsg(int fd, IxpMsg *msg);
+
+ uint ixp_recvmsg(int fd, IxpMsg *msg);
+.fi
+
+.SH DESCRIPTION
+.P
+These functions read and write messages to and from the given
+file descriptors.
+
+.P
+ixp_sendmsg writes the data at \fImsg\fR\->pos upto \fImsg\fR\->end.
+If the call returns non\-zero, all data is assured to have
+been written.
+
+.P
+ixp_recvmsg first reads a 32 bit, little\-endian length from
+\fIfd\fR and then reads a message of that length (including the
+4 byte size specifier) into the buffer at \fImsg\fR\->data, so
+long as the size is less than \fImsg\fR\->size.
+
+.SH RETURN VALUE
+.P
+These functions return the number of bytes read or
+written, or 0 on error. Errors are stored in
+\fBixp_errbuf(3)\fR.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_sendmsg.man3
+
diff --git a/man/ixp_serverloop.3 b/man/ixp_serverloop.3
@@ -6,6 +6,8 @@ ixp_serverloop, IxpServer
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
int ixp_serverloop(IxpServer *srv);
typedef struct IxpServer IxpServer;
diff --git a/man/ixp_settimer.3 b/man/ixp_settimer.3
@@ -6,6 +6,8 @@ ixp_settimer
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
long ixp_settimer(IxpServer *srv, long msec, void (*fn)(long, void *), void *aux);
.fi
diff --git a/man/ixp_smprint.3 b/man/ixp_smprint.3
@@ -0,0 +1,22 @@
+.TH "IXP_SMPRINT" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_smprint
+
+.SH SYNOPSIS
+.nf
+ #include <ixp.h>
+
+ char *ixp_smprint(const char *fmt, ...);
+.fi
+
+.SH DESCRIPTION
+.P
+This function formats its arguments as \fBprintf(3)\fR and returns
+a \fBmalloc(3)\fR allocated string containing the result.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_smprint.man3
+
diff --git a/man/ixp_srv_clonefiles.3 b/man/ixp_srv_clonefiles.3
@@ -6,6 +6,8 @@ ixp_srv_clonefiles
.SH SYNOPSIS
.nf
+ #include <ixp_srvutil.h>
+
IxpFileId *ixp_srv_clonefiles(IxpFileId *fileid);
.fi
diff --git a/man/ixp_srv_data2cstring.3 b/man/ixp_srv_data2cstring.3
@@ -6,6 +6,8 @@ ixp_srv_data2cstring
.SH SYNOPSIS
.nf
+ #include <ixp_srvutil.h>
+
void ixp_srv_data2cstring(Ixp9Req *req);
.fi
diff --git a/man/ixp_srv_freefile.3 b/man/ixp_srv_freefile.3
@@ -6,6 +6,8 @@ ixp_srv_freefile
.SH SYNOPSIS
.nf
+ #include <ixp_srvutil.h>
+
void ixp_srv_freefile(IxpFileId *fileid);
.fi
diff --git a/man/ixp_srv_getfile.3 b/man/ixp_srv_getfile.3
@@ -6,6 +6,8 @@ ixp_srv_getfile, IxpFileId
.SH SYNOPSIS
.nf
+ #include <ixp_srvutil.h>
+
IxpFileId *ixp_srv_getfile(void);
typedef struct IxpFileId IxpFileId;
@@ -16,7 +18,7 @@ ixp_srv_getfile, IxpFileId
uint id;
uint index;
IxpDirtab tab;
- ushort nref;
+ uint nref;
uchar volatil;
}
.fi
diff --git a/man/ixp_srv_readbuf.3 b/man/ixp_srv_readbuf.3
@@ -0,0 +1,40 @@
+.TH "IXP_SRV_READBUF" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_readbuf, ixp_srv_writebuf
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_srv_readbuf(Ixp9Req *req, char *buf, uint len);
+
+ void ixp_srv_writebuf(Ixp9Req *req, char **buf, uint *len, uint max);
+.fi
+
+.SH DESCRIPTION
+.P
+Utility functions for handling TRead and TWrite requests for
+files backed by in\-memory buffers. For both functions, \fIbuf\fR
+points to a buffer and \fIlen\fR specifies the length of the
+buffer. In the case of ixp_srv_writebuf, these values add a
+level of pointer indirection, and updates the values if they
+change.
+
+.P
+If \fImax\fR has a value other than 0, ixp_srv_writebuf will
+truncate any writes to that point in the buffer. Otherwise,
+\fI*buf\fR is assumed to be malloc(3) allocated, and is
+reallocated to fit the new data as necessary. The buffer is
+is always left nul\-terminated.
+
+.SH BUGS
+.P
+ixp_srv_writebuf always truncates its buffer to the end
+of the most recent write.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_readbuf.man3
+
diff --git a/man/ixp_srv_walkandclone.3 b/man/ixp_srv_walkandclone.3
@@ -0,0 +1,58 @@
+.TH "IXP_SRV_WALKANDCLONE" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_walkandclone, ixp_srv_readdir, ixp_srv_verifyfile, IxpLookupFn
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ void ixp_srv_walkandclone(Ixp9Req *req, IxpLookupFn lookup);
+
+ void ixp_srv_readdir(Ixp9Req *req, IxpLookupFn lookup, void (*dostat)(Stat *, IxpFileId *));
+
+ bool ixp_srv_verifyfile(IxpFileId *file, IxpLookupFn lookup);
+
+ typedef IxpFileId* (*IxpLookupFn)(IxpFileId*, char*);
+.fi
+
+.SH DESCRIPTION
+.P
+These convenience functions simplify the writing of basic and
+static file servers. They use a generic file lookup function
+to simplify the process of walking, cloning, and returning
+directory listings. Given the \fBIxpFileId(3)\fR of a directory and a
+filename name should return a new IxpFileId (allocated via
+\fBixp_srv_getfile(3)\fR) for the matching directory entry, or null
+if there is no match. If the passed name is null, \fIlookup\fR
+should return a linked list of IxpFileIds, one for each child
+directory entry.
+
+.P
+ixp_srv_walkandclone handles the moderately complex process
+of walking from a directory entry and cloning fids, and calls
+\fBixp_respond(3)\fR. It should be called in response to a TWalk
+request.
+
+.P
+ixp_srv_readdir should be called to handle read requests on
+directories. It prepares a stat for each child of the
+directory, taking into account the requested offset, and
+calls \fBixp_respond(3)\fR. The \fIdostat\fR parameter must be a
+function which fills the passed \fBIxpStat(3)\fR pointer based on
+the contents of the passed IxpFileId.
+
+.P
+ixp_srv_verifyfile returns whether a file still exists in the
+filesystem, and should be used by filesystems that invalidate
+files once they have been deleted.
+
+.SH SEE ALSO
+.P
+IxpFileId(3), ixp_getfile(3), ixp_freefile(3)
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_walkandclone.man3
+
diff --git a/man/ixp_srv_writectl.3 b/man/ixp_srv_writectl.3
@@ -0,0 +1,28 @@
+.TH "IXP_SRV_WRITECTL" 3 "2010 Jun" "libixp Manual"
+
+.SH NAME
+.P
+ixp_srv_writectl
+
+.SH SYNOPSIS
+.nf
+ #include <ixp_srvutil.h>
+
+ char *ixp_srv_writectl(Ixp9Req *req, char *(*fn)(void *, IxpMsg *));
+.fi
+
+.SH DESCRIPTION
+.P
+This utility function is meant to simplify the writing of
+pseudo files to which single\-lined commands are written.
+In order to use this function, the \fIaux\fR member of
+\fIreq\fR\->fid must be nul or an \fBIxpFileId(3)\fR. Each line of the
+written data is stripped of its trailing newline,
+nul\-terminated, and stored in an \fBIxpMsg(3)\fR. For each line
+thus prepared, \fIfn\fR is called with the IxpMsg pointer and
+the the \fIp\fR member of the IxpFileId.
+
+
+.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
+.\" cmdline: txt2tags -o- ixp_srv_writectl.man3
+
diff --git a/man/ixp_stat.3 b/man/ixp_stat.3
@@ -6,19 +6,21 @@ ixp_stat, ixp_fstat, IxpStat, IxpQid, IxpQType, IxpDMode
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
Stat *ixp_stat(IxpClient *c, const char *path);
Stat *ixp_fstat(IxpCFid *fid);
typedef struct IxpStat IxpStat;
struct IxpStat {
- ushort type;
- ulong dev;
- IxpQid qid;
- ulong mode;
- ulong atime;
- ulong mtime;
- uvlong length;
+ uint16_t type;
+ uint32_t dev;
+ IxpQid qid;
+ uint32_t mode;
+ uint32_t atime;
+ uint32_t mtime;
+ uint64_t length;
char* name;
char* uid;
char* gid;
@@ -27,9 +29,9 @@ ixp_stat, ixp_fstat, IxpStat, IxpQid, IxpQType, IxpDMode
typedef struct IxpQid IxpQid;
struct IxpQid {
- uchar type;
- ulong version;
- uvlong path;
+ uint8_t type;
+ uint32_t version;
+ uint64_t path;
/* Private members */
...
}
diff --git a/man/ixp_unmount.3 b/man/ixp_unmount.3
@@ -6,6 +6,8 @@ ixp_unmount
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
void ixp_unmount(IxpClient *client);
.fi
diff --git a/man/ixp_unsettimer.3 b/man/ixp_unsettimer.3
@@ -6,6 +6,8 @@ ixp_unsettimer
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
int ixp_unsettimer(IxpServer *srv, long id);
.fi
diff --git a/man/ixp_vprint.3 b/man/ixp_vprint.3
@@ -1,57 +0,0 @@
-.TH "IXP_VPRINT" 3 "2010 Jun" "libixp Manual"
-
-.SH NAME
-.P
-ixp_vprint, ixp_print, ixp_vsmprint
-
-.SH SYNOPSIS
-.nf
- ixp_vprint
-
- int ixp_print(IxpCFid *fid, const char *fmt, ...);
-
- ixp_vsmprint
-.fi
-
-.SH PARAMETERS
-.TP
-fid
-An open IxpCFid to which to write the result.
-.TP
-fmt
-The string with which to format the data.
-.TP
-args
-A va_list holding the arguments to the format
-string.
-.TP
-.RB ...
-The arguments to the format string.
-
-.SH DESCRIPTION
-.P
-These functions act like the standard formatted IO
-functions. They write the result of the formatting to the
-file pointed to by C<fid>.
-
-.P
-\fBixp_vsmprint(3)\fR may be set to a function which will
-format its arguments and return a nul\-terminated string
-allocated by malloc(3). The default formats its arguments as
-printf(3). The function must format '%s' as a nul\-terminated
-string and may not consume any arguments not specified by a
-manner chosen by the user.
-
-.SH RETURN VALUE
-.P
-These functions return the number of bytes written.
-There is currently no way to detect failure.
-
-.SH SEE ALSO
-.P
-ixp_mount(3), ixp_open(3), printf(3)
-
-
-.\" man code generated by txt2tags 2.5 (http://txt2tags.sf.net)
-.\" cmdline: txt2tags -o- ixp_vprint.man3
-
diff --git a/man/ixp_write.3 b/man/ixp_write.3
@@ -6,9 +6,11 @@ ixp_write, ixp_pwrite
.SH SYNOPSIS
.nf
+ #include <ixp.h>
+
long ixp_write(IxpCFid *fid, const void *buf, long count);
- long ixp_pwrite(IxpCFid *fid, const void *buf, long count, vlong offset);
+ long ixp_pwrite(IxpCFid *fid, const void *buf, long count, int64_t offset);
.fi
.SH PARAMETERS
diff --git a/man/targets.mk b/man/targets.mk
@@ -1,4 +1,7 @@
MANPAGES = \
+ 'IxpFcall.3 IxpFType.3 IxpFAttach.3 IxpFError.3 IxpFHdr.3 IxpFIO.3 IxpFRAuth.3 IxpFROpen.3 IxpFRStat.3 IxpFRWalk.3 IxpFTCreate.3 IxpFTFlush.3 IxpFTWStat.3 IxpFTWalk.3 IxpFVersion.3' \
+ 'IxpFid.3' \
+ 'IxpThread.3 IxpMutex.3 IxpRWLock.3 IxpRendez.3 ixp_thread.3' \
'ixp_unmount.3' \
'ixp_mount.3 ixp_mountfd.3 ixp_nsmount.3 IxpClient.3' \
'ixp_remove.3' \
@@ -7,8 +10,19 @@ MANPAGES = \
'ixp_stat.3 ixp_fstat.3 IxpStat.3 IxpQid.3 IxpQType.3 IxpDMode.3' \
'ixp_read.3 ixp_pread.3' \
'ixp_write.3 ixp_pwrite.3' \
- 'ixp_vprint.3 ixp_print.3 ixp_vsmprint.3' \
- 'ixp_errbuf.3 ixp_errstr.3 ixp_rerrstr.3 ixp_werrstr.3' \
+ 'ixp_print.3 ixp_vprint.3 ixp_vsmprint.3' \
+ 'ixp_pu8.3 ixp_pu16.3 ixp_pu32.3 ixp_pu64.3' \
+ 'ixp_pstring.3' \
+ 'ixp_pstrings.3' \
+ 'ixp_pdata.3' \
+ 'ixp_pfcall.3 ixp_pqid.3 ixp_pqids.3 ixp_pstat.3 ixp_sizeof_stat.3' \
+ 'ixp_errbuf.3 ixp_errstr.3 ixp_rerrstr.3 ixp_werrstr.3 ixp_vsnprint.3' \
+ 'IxpMsg.3 IxpMsgMode.3 ixp_message.3' \
+ 'ixp_freestat.3 ixp_freefcall.3' \
+ 'ixp_fcall2msg.3 ixp_msg2fcall.3' \
+ 'ixp_printfcall.3' \
+ 'ixp_respond.3' \
+ 'Ixp9Srv.3 Ixp9Req.3 ixp_serve9conn.3' \
'ixp_listen.3 IxpConn.3' \
'ixp_hangup.3 ixp_server_close.3' \
'ixp_serverloop.3 IxpServer.3' \
@@ -16,9 +30,16 @@ MANPAGES = \
'ixp_srv_getfile.3 IxpFileId.3' \
'ixp_srv_freefile.3' \
'ixp_srv_clonefiles.3' \
+ 'ixp_srv_readbuf.3 ixp_srv_writebuf.3' \
'ixp_srv_data2cstring.3' \
+ 'ixp_srv_writectl.3' \
+ 'ixp_pending_write.3 ixp_pending_pushfid.3 ixp_pending_clunk.3 ixp_pending_flush.3 ixp_pending_respond.3 IxpPending.3' \
+ 'ixp_srv_walkandclone.3 ixp_srv_readdir.3 ixp_srv_verifyfile.3 IxpLookupFn.3' \
'ixp_msec.3' \
'ixp_settimer.3' \
'ixp_unsettimer.3' \
- 'ixp_nexttimer.3' \
- 'ixp_namespace.3'
+ 'ixp_sendmsg.3 ixp_recvmsg.3' \
+ 'ixp_smprint.3' \
+ 'ixp_namespace.3' \
+ 'ixp_eprint.3' \
+ 'ixp_emalloc.3 ixp_emallocz.3 ixp_erealloc.3 ixp_estrdup.3'
diff --git a/util/grepdoc b/util/grepdoc
@@ -20,10 +20,11 @@ my @c = grep /\.c$/, @ARGV;
my @h = grep /\.h$/, @ARGV;
my %protos;
+my %headers;
open(my $stderr, '>&', \*STDERR);
open STDERR, '>', '/dev/null';
-open my $fd, '-|', 'cproto', '-I./include', @c;
+open my $fd, '-|', 'cproto', '-DCPROTO', '-I./include', @c, '/dev/null';
for(<$fd>) {
chomp;
s/\b_ixp//g;
@@ -33,20 +34,41 @@ for(<$fd>) {
}
open STDERR, '>&', $stderr;
-@ARGV = @h;
-$_ = join "", map detab, <>;
+my @txt;
+@ARGV = (@h, '/dev/null');
+for my $f(@h) {
+ open my $fd, '<', $f;
+ $_ = join "", map detab, <$fd>;
+ push @txt, $_;
-while(m/^typedef\b.*?(\w+);/gm) {
- push @{$protos{$1}}, $& unless $& =~ m{\Q/* Deprecated */};
-}
-while(m/^(?:enum|struct)\s+(\w+).*?^\}/gsm) {
- my $proto = \@{$protos{$1}};
- push @$proto, subst {"$1$2$1..."} qr[(^ +)(\Q/* Private members */\E\n).*(?=\n\})]sm, $&
- unless $& =~ m{\Q/* Deprecated */};
+ $f =~ s|^(\./)?include/||;
+
+ my $junk = qr/(?:\[.*\]|\)\(.*\))?/;
+ while(m/^extern\s+(.*\b(\w+)$junk;)$/gm) {
+ $headers{$2} = $f;
+ push @{$protos{$2}}, $1;
+ }
+ while(m/^(?!extern)[a-z][^(]+\b(\w+)\(/gmi) {
+ my $id = $1;
+ $headers{$id} = $f unless $& =~ m{^\s*(?:#|//|/\*|\*)};
+ }
+ while(m/^typedef\b.*?\b(\w+)$junk;/gm) {
+ $headers{$1} = $f;
+ push @{$protos{$1}}, $& unless $& =~ m{\Q/* Deprecated */};
+ }
+ while(m/^(?:enum|struct|union)\s+(\w+).*?^\}/gsm) {
+ $headers{$1} = $f;
+ my $proto = \@{$protos{$1}};
+ push @$proto, subst {"$1$2$1..."} qr[(^ +)(\Q/* Private members */\E\n).*(?=\n\})]sm, $&
+ unless $& =~ m{\Q/* Deprecated */};
+ }
}
-@ARGV = @c;
-$_ .= join "", map detab, <>;
+# print Data::Dumper->Dump([\%protos], ['%protos']);
+# print Data::Dumper->Dump([\%headers], ['%headers']);
+
+@ARGV = (@c, '/dev/null');
+$_ = join "", @txt, map detab, <>;
sub section($$) {
my ($sect, $text) = @_;
@@ -79,6 +101,10 @@ while(m{(?<=/\*\*\n)(?:[^*]|\*[^/])+}g) {
next;
}
+ my %hdrs = map {($headers{$_}, "")} @names;
+ my $includes = join "", map {"#include <$_>\n"} sort keys %hdrs;
+ $header = "$includes\n$header" if $includes;
+
sub despace {
my ($space) = m/^(\s*)/;
s/^$space//gm;
diff --git a/util/link b/util/link
@@ -27,7 +27,7 @@ echo LD "$($bin/cleanname ${BASE}$outfile)"
[ -n "$noisycc" ] && echo $LD -o $outfile $ofiles $LDFLAGS $args
$LD -o $outfile $ofiles $LDFLAGS $args >$xtmp 2>&1
status=$?
-[ $status -eq 0 ] || $LD -o $outfile $ofiles $LDFLAGS $args >&2
+[ $status -eq 0 ] || echo $LD -o $outfile $ofiles $LDFLAGS $args >&2
sed 's/.*: In function `[^:]*: *//' $xtmp | egrep . |
egrep -v 'is almost always misused|is dangerous, better use|in statically linked applications requires at runtime'