summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/sbc_harness/fs_harness_flash_bin.c66
-rw-r--r--cmd/sbc_harness/fs_harness_uptime_txt.c43
-rw-r--r--cmd/sbc_harness/main.c4
-rw-r--r--lib9p/srv.c121
-rw-r--r--lib9p/srv_include/lib9p/srv.h153
-rw-r--r--lib9p/tests/test_server/fs_flush.c46
-rw-r--r--lib9p/tests/test_server/fs_shutdown.c31
-rw-r--r--lib9p/tests/test_server/fs_whoami.c44
-rw-r--r--lib9p/tests/test_server/main.c6
-rw-r--r--lib9p/tests/testclient-sess.explog2
-rw-r--r--lib9p_util/static.c121
11 files changed, 322 insertions, 315 deletions
diff --git a/cmd/sbc_harness/fs_harness_flash_bin.c b/cmd/sbc_harness/fs_harness_flash_bin.c
index d3f90b9..ea60447 100644
--- a/cmd/sbc_harness/fs_harness_flash_bin.c
+++ b/cmd/sbc_harness/fs_harness_flash_bin.c
@@ -148,11 +148,11 @@ static struct lib9p_qid flash_file_qid(struct flash_file *self) {
};
}
-static struct lib9p_srv_stat flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error flash_file_stat(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = flash_file_qid(self),
.mode = LIB9P_DM_EXCL|0666,
.atime_sec = UTIL9P_ATIME,
@@ -163,25 +163,25 @@ static struct lib9p_srv_stat flash_file_stat(struct flash_file *self, struct lib
.owner_gid = { .name = lib9p_str("root"), .num = 0 },
.last_modifier_uid = { .name = lib9p_str("root"), .num = 0 },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+static error flash_file_wstat(struct flash_file *self, struct lib9p_srv_ctx *ctx,
struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void flash_file_remove(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
+static error flash_file_remove(struct flash_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
LIB9P_SRV_NOTDIR(struct flash_file, flash_file);
-static lo_interface lib9p_srv_fio flash_file_fopen(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+static lib9p_srv_fio_or_error flash_file_fopen(struct flash_file *self, struct lib9p_srv_ctx *ctx,
bool rd, bool wr, bool trunc) {
assert(self);
assert(ctx);
@@ -201,7 +201,7 @@ static lo_interface lib9p_srv_fio flash_file_fopen(struct flash_file *self, stru
self->wbuf.ok = false;
}
- return LO_BOX(lib9p_srv_fio, self);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, self));
}
/* srv_fio ********************************************************************/
@@ -221,17 +221,13 @@ static void flash_file_iofree(struct flash_file *self) {
ab_flash_finalize(self->wbuf.dat);
}
-static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
+static iovec_or_error flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t byte_offset) {
assert(self);
assert(ctx);
- assert(ret);
- if (byte_offset > DATA_SIZE) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is past the chip size");
- return;
- }
+ if (byte_offset > DATA_SIZE)
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EINVAL, "offset is past the chip size"));
/* Assume that somewhere down the line the iovec we return
* will be passed to DMA. We don't want the DMA engine to hit
@@ -240,12 +236,10 @@ static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
* data to a buffer in (fast) RAM first. It's lame that the
* DMA engine can only have a DREQ on one side of the channel.
*/
- if (byte_offset == DATA_SIZE) {
- *ret = (struct iovec){
+ if (byte_offset == DATA_SIZE)
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
.iov_len = 0,
- };
- return;
- }
+ }));
size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
byte_count = (sector_base + FLASH_SECTOR_SIZE) - byte_offset;
@@ -257,32 +251,28 @@ static void flash_file_pread(struct flash_file *self, struct lib9p_srv_ctx *ctx,
memcpy(self->rbuf.dat, DATA_START+sector_base, FLASH_SECTOR_SIZE);
}
- *ret = (struct iovec){
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
.iov_base = &self->rbuf.dat[byte_offset-sector_base],
.iov_len = byte_count,
- };
+ }));
}
/* TODO: Short/corrupt writes are dangerous. This should either (1)
* check a checksum, (2) use uf2 instead of verbatim data, or (3) use
* ihex instead of verbatim data. */
-static uint32_t flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx *ctx,
- void *buf,
- uint32_t byte_count,
- uint64_t byte_offset) {
+static uint32_t_or_error flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx *ctx,
+ void *buf,
+ uint32_t byte_count,
+ uint64_t byte_offset) {
assert(self);
assert(ctx);
- if (byte_offset > DATA_HSIZE) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is past half the chip size");
- return 0;
- }
+ if (byte_offset > DATA_HSIZE)
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EINVAL, "offset is past half the chip size"));
if (byte_count == 0)
- return 0;
- if (byte_offset == DATA_HSIZE) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is at half the chip size");
- return 0;
- }
+ return ERROR_NEW_VAL(uint32_t, 0);
+ if (byte_offset == DATA_HSIZE)
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EINVAL, "offset is at half the chip size"));
size_t sector_base = LM_ROUND_DOWN(byte_offset, FLASH_SECTOR_SIZE);
if (byte_offset + byte_count > sector_base + FLASH_SECTOR_SIZE)
@@ -300,5 +290,5 @@ static uint32_t flash_file_pwrite(struct flash_file *self, struct lib9p_srv_ctx
memcpy(&self->wbuf.dat[byte_offset-sector_base], buf, byte_count);
self->written = true;
- return byte_count;
+ return ERROR_NEW_VAL(uint32_t, byte_count);
}
diff --git a/cmd/sbc_harness/fs_harness_uptime_txt.c b/cmd/sbc_harness/fs_harness_uptime_txt.c
index 2533558..021a8bd 100644
--- a/cmd/sbc_harness/fs_harness_uptime_txt.c
+++ b/cmd/sbc_harness/fs_harness_uptime_txt.c
@@ -37,7 +37,7 @@ static struct lib9p_qid uptime_file_qid(struct uptime_file *self) {
};
}
-static struct lib9p_srv_stat uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error uptime_file_stat(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
@@ -51,7 +51,7 @@ static struct lib9p_srv_stat uptime_file_stat(struct uptime_file *self, struct l
size++;
size += 3;
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = uptime_file_qid(self),
.mode = 0444,
.atime_sec = UTIL9P_ATIME,
@@ -62,26 +62,26 @@ static struct lib9p_srv_stat uptime_file_stat(struct uptime_file *self, struct l
.owner_gid = { .name = lib9p_str("root"), .num = 0 },
.last_modifier_uid = { .name = lib9p_str("root"), .num = 0 },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_srv_stat) {
+static error uptime_file_wstat(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void uptime_file_remove(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
+static error uptime_file_remove(struct uptime_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
LIB9P_SRV_NOTDIR(struct uptime_file, uptime_file);
-static lo_interface lib9p_srv_fio uptime_file_fopen(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
- bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) {
+static lib9p_srv_fio_or_error uptime_file_fopen(struct uptime_file *self, struct lib9p_srv_ctx *ctx,
+ bool LM_UNUSED(rd), bool LM_UNUSED(wr), bool LM_UNUSED(trunc)) {
assert(self);
assert(ctx);
@@ -89,7 +89,7 @@ static lo_interface lib9p_srv_fio uptime_file_fopen(struct uptime_file *self, st
ret->parent = self;
ret->buf_len = 0;
- return LO_BOX(lib9p_srv_fio, ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -110,40 +110,35 @@ static struct lib9p_qid uptime_fio_qid(struct uptime_fio *self) {
return uptime_file_qid(self->parent);
}
-static void uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
+static iovec_or_error uptime_fio_pread(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t byte_offset) {
assert(self);
assert(ctx);
- assert(ret);
if (byte_offset == 0 || self->buf_len == 0) {
uint64_t now = LO_CALL(bootclock, get_time_ns);
self->buf_len = fmt_snprint(self->buf, sizeof(self->buf), now, "ns\n");
}
- if (byte_offset > (uint64_t)self->buf_len) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is past end-of-file length");
- return;
- }
+ if (byte_offset > (uint64_t)self->buf_len)
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EINVAL, "offset is past end-of-file length"));
size_t beg_off = (size_t)byte_offset;
size_t end_off = beg_off + (size_t)byte_count;
if (end_off > self->buf_len)
end_off = self->buf_len;
- *ret = (struct iovec){
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
.iov_base = &self->buf[beg_off],
.iov_len = end_off-beg_off,
- };
+ }));
}
-static uint32_t uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
+static uint32_t_or_error uptime_fio_pwrite(struct uptime_fio *self, struct lib9p_srv_ctx *ctx,
void *LM_UNUSED(buf),
uint32_t LM_UNUSED(byte_count),
uint64_t LM_UNUSED(byte_offset)) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
- return 0;
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
}
diff --git a/cmd/sbc_harness/main.c b/cmd/sbc_harness/main.c
index d32b775..82519ae 100644
--- a/cmd/sbc_harness/main.c
+++ b/cmd/sbc_harness/main.c
@@ -114,8 +114,8 @@ static struct lib9p_srv_file root =
),
);
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
- return root;
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
+ return ERROR_NEW_VAL(lib9p_srv_file, root);
}
/* Code ***********************************************************************/
diff --git a/lib9p/srv.c b/lib9p/srv.c
index 917b41e..05d7144 100644
--- a/lib9p/srv.c
+++ b/lib9p/srv.c
@@ -44,28 +44,66 @@ static_assert(CONFIG_9P_SRV_MAX_HOSTMSG_SIZE <= SSIZE_MAX);
/* context ********************************************************************/
-void lib9p_ctx_clear_error(struct lib9p_srv_ctx *ctx) {
+static void lib9p_ctx_clear_error(struct lib9p_srv_ctx *ctx) {
assert(ctx);
ctx->err_num = 0;
ctx->err_msg[0] = '\0';
}
-bool lib9p_ctx_has_error(struct lib9p_srv_ctx *ctx) {
+static bool lib9p_ctx_has_error(struct lib9p_srv_ctx *ctx) {
assert(ctx);
return ctx->err_msg[0];
}
+/** Write a <libmisc/fmt.h>-style error into ctx, return -1. */
+#define lib9p_error(ctx, libmisc_errno, ...) ({ \
+ if (!lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = libmisc_errno; \
+ struct fmt_buf _w = { \
+ .dat = (ctx)->err_msg, \
+ .cap = sizeof((ctx)->err_msg), \
+ }; \
+ lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \
+ fmt_print(w, __VA_ARGS__); \
+ if (_w.len < _w.cap) \
+ memset(_w.dat + _w.len, 0, _w.cap - _w.len); \
+ } \
+ -1; \
+})
+
+#define CTX_ERR_OR(TYP, func, ctx, ...) \
+ ({ \
+ TYP##_or_error r = func(ctx __VA_OPT__(,) __VA_ARGS__); \
+ TYP v = {}; \
+ if (r.is_err && !lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = r.err.num; \
+ strncpy((ctx)->err_msg, error_msg(r.err), CONFIG_9P_SRV_MAX_ERR_SIZE); \
+ error_cleanup(&r.err); \
+ } \
+ if (!r.is_err) \
+ v = r.TYP; \
+ v; \
+ })
+
+#define CTX_LO_ERR_OR(TYP, obj, func, ctx, ...) \
+ ({ \
+ TYP##_or_error r = LO_CALL(obj, func, ctx __VA_OPT__(,) __VA_ARGS__); \
+ TYP v = {}; \
+ if (r.is_err && !lib9p_ctx_has_error(ctx)) { \
+ (ctx)->err_num = r.err.num; \
+ strncpy((ctx)->err_msg, error_msg(r.err), CONFIG_9P_SRV_MAX_ERR_SIZE); \
+ error_cleanup(&r.err); \
+ } \
+ if (!r.is_err) \
+ v = r.TYP; \
+ v; \
+ })
+
bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx) {
assert(ctx);
return cr_chan_can_send(&ctx->flush_ch);
}
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) {
- assert(ctx);
- assert(cr_chan_can_send(&ctx->flush_ch));
- ctx->flush_acknowledged = true;
-}
-
#define req_debug(...) \
log_debugln( \
"cid=", cr_getcid(), ": ", \
@@ -707,10 +745,12 @@ void lib9p_srv_worker(struct srv_req *ctx) {
static inline void _srv_respond(struct srv_req *ctx, enum lib9p_msg_type resp_typ, void *host_resp) {
assert(!ctx->responded);
if (lib9p_ctx_has_error(ctx)) {
- error:
- srv_respond_error(ctx);
- } else if (ctx->flush_acknowledged) {
- /* do nothing */
+ if (ctx->err_num == E_POSIX_ECANCELED && lib9p_srv_flush_requested(ctx)) {
+ /* do nothing */
+ } else {
+ error:
+ srv_respond_error(ctx);
+ }
} else {
assert(host_resp);
struct lib9p_Rmsg_send_buf net_resp;
@@ -893,7 +933,7 @@ static void handle_Tattach(struct srv_req *ctx,
}
/* 1. File object */
- lo_interface lib9p_srv_file root_file = srv->rootdir(ctx, req->aname);
+ lo_interface lib9p_srv_file root_file = CTX_ERR_OR(lib9p_srv_file, srv->rootdir, ctx, req->aname);
assert(LO_IS_NULL(root_file) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto tattach_return;
@@ -929,12 +969,14 @@ static void handle_Tflush(struct srv_req *ctx,
CR_SELECT_SEND(&ctx->flush_ch, &res))) {
case 0: /* original request returned */
req_debug("original request (tag=", req->oldtag, ") returned");
- ctx->flush_acknowledged = (res == _LIB9P_SRV_FLUSH_SILENT);
+ if (res == _LIB9P_SRV_FLUSH_SILENT) {
+ ctx->responded = true;
+ return;
+ }
break;
case 1: /* flush itself got flushed */
- req_debug("flush itself flushed");
- ctx->flush_acknowledged = true;
- break;
+ ctx->responded = true;
+ return;
}
}
srv_respond(ctx, flush, &resp);
@@ -978,7 +1020,7 @@ static void handle_Twalk(struct srv_req *ctx,
assert(new_pathinfo);
new_pathinfo->gc_refcount++;
} else {
- lo_interface lib9p_srv_file member_file = LO_CALL(pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]);
+ lo_interface lib9p_srv_file member_file = CTX_LO_ERR_OR(lib9p_srv_file, pathinfo->file, dwalk, ctx, req->wname[resp.nwqid]);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
break;
@@ -987,7 +1029,7 @@ static void handle_Twalk(struct srv_req *ctx,
}
if (new_pathinfo->type == SRV_FILETYPE_DIR) {
- struct lib9p_srv_stat stat = LO_CALL(new_pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, new_pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
break;
lib9p_srv_stat_assert(stat);
@@ -1052,7 +1094,7 @@ static void handle_Topen(struct srv_req *ctx,
if (reqmode & LIB9P_O_RCLOSE) {
struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
assert(parent);
- struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx);
+ struct lib9p_srv_stat parent_stat = CTX_LO_ERR_OR(lib9p_srv_stat, parent->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto topen_return;
lib9p_srv_stat_assert(parent_stat);
@@ -1062,7 +1104,7 @@ static void handle_Topen(struct srv_req *ctx,
}
fidflags |= FIDFLAG_RCLOSE;
}
- struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto topen_return;
lib9p_srv_stat_assert(stat);
@@ -1104,7 +1146,7 @@ static void handle_Topen(struct srv_req *ctx,
struct lib9p_qid qid;
switch (pathinfo->type) {
case SRV_FILETYPE_DIR:
- fidinfo->dir.io = LO_CALL(pathinfo->file, dopen, ctx);
+ fidinfo->dir.io = CTX_LO_ERR_OR(lib9p_srv_dio, pathinfo->file, dopen, ctx);
assert(LO_IS_NULL(fidinfo->dir.io) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto topen_return;
@@ -1114,9 +1156,9 @@ static void handle_Topen(struct srv_req *ctx,
iounit = 0;
break;
case SRV_FILETYPE_FILE:
- fidinfo->file.io = LO_CALL(pathinfo->file, fopen, ctx,
- rd, wr,
- reqmode & LIB9P_O_TRUNC);
+ fidinfo->file.io = CTX_LO_ERR_OR(lib9p_srv_fio, pathinfo->file, fopen, ctx,
+ rd, wr,
+ reqmode & LIB9P_O_TRUNC);
assert(LO_IS_NULL(fidinfo->file.io) == lib9p_ctx_has_error(ctx));
if (lib9p_ctx_has_error(ctx))
goto topen_return;
@@ -1220,7 +1262,7 @@ static void handle_Tread(struct srv_req *ctx,
if (fidinfo->dir.buffered_dirent.name.len) {
member_dirent = fidinfo->dir.buffered_dirent;
} else {
- member_dirent = LO_CALL(fidinfo->dir.io, dread, ctx, fidinfo->dir.idx);
+ member_dirent = CTX_LO_ERR_OR(lib9p_srv_dirent, fidinfo->dir.io, dread, ctx, fidinfo->dir.idx);
if (lib9p_ctx_has_error(ctx)) {
if (!resp.count)
goto tread_return;
@@ -1233,17 +1275,23 @@ static void handle_Tread(struct srv_req *ctx,
struct lib9p_srv_stat member_stat;
struct srv_pathinfo *member_pathinfo = map_load(&ctx->parent_sess->paths, member_dirent.qid.path);
if (member_pathinfo) {
- member_stat = LO_CALL(member_pathinfo->file, stat, ctx);
+ member_stat = CTX_LO_ERR_OR(lib9p_srv_stat, member_pathinfo->file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
} else {
if (!dir_pathinfo)
dir_pathinfo = map_load(&ctx->parent_sess->paths, fidinfo->path);
assert(dir_pathinfo);
- member_file = LO_CALL(dir_pathinfo->file, dwalk, ctx, member_dirent.name);
+ member_file = CTX_LO_ERR_OR(lib9p_srv_file, dir_pathinfo->file, dwalk, ctx, member_dirent.name);
assert(LO_IS_NULL(member_file) == lib9p_ctx_has_error(ctx));
- if (!lib9p_ctx_has_error(ctx))
- member_stat = LO_CALL(member_file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
+ member_stat = CTX_LO_ERR_OR(lib9p_srv_stat, member_file, stat, ctx);
+ if (lib9p_ctx_has_error(ctx))
+ goto member_err;
}
- if (lib9p_ctx_has_error(ctx)) {
+ if (false) {
+ member_err:
if (!LO_IS_NULL(member_file))
LO_CALL(member_file, free);
if (!resp.count)
@@ -1275,9 +1323,8 @@ static void handle_Tread(struct srv_req *ctx,
#endif
break;
case SRV_FILETYPE_FILE:
- struct iovec iov;
- LO_CALL(fidinfo->file.io, pread, ctx, req->count, req->offset, &iov);
- if (!lib9p_ctx_has_error(ctx) && !ctx->flush_acknowledged) {
+ struct iovec iov = CTX_LO_ERR_OR(iovec, fidinfo->file.io, pread, ctx, req->count, req->offset);
+ if (!lib9p_ctx_has_error(ctx)) {
resp.count = iov.iov_len;
resp.data = iov.iov_base;
if (resp.count > req->count)
@@ -1317,7 +1364,7 @@ static void handle_Twrite(struct srv_req *ctx,
/* Do it. */
ctx->user = srv_userid_incref(fidinfo->user);
- resp.count = LO_CALL(fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
+ resp.count = CTX_LO_ERR_OR(uint32_t, fidinfo->file.io, pwrite, ctx, req->data, req->count, req->offset);
twrite_return:
if (ctx->user)
ctx->user = srv_userid_decref(ctx->user);
@@ -1360,7 +1407,7 @@ static void handle_Tremove(struct srv_req *ctx,
}
struct srv_pathinfo *parent = map_load(&ctx->parent_sess->paths, pathinfo->parent_dir);
assert(parent);
- struct lib9p_srv_stat parent_stat = LO_CALL(parent->file, stat, ctx);
+ struct lib9p_srv_stat parent_stat = CTX_LO_ERR_OR(lib9p_srv_stat, parent->file, stat, ctx);
if (!lib9p_ctx_has_error(ctx) && !srv_check_perm(ctx, &parent_stat, 0b010)) {
lib9p_error(ctx, E_POSIX_EACCES, "you do not have write permission on the parent directory");
remove = false;
@@ -1386,7 +1433,7 @@ static void handle_Tstat(struct srv_req *ctx,
assert(pathinfo);
ctx->user = srv_userid_incref(fidinfo->user);
- struct lib9p_srv_stat stat = LO_CALL(pathinfo->file, stat, ctx);
+ struct lib9p_srv_stat stat = CTX_LO_ERR_OR(lib9p_srv_stat, pathinfo->file, stat, ctx);
if (lib9p_ctx_has_error(ctx))
goto tstat_return;
lib9p_srv_stat_assert(stat);
diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h
index 77a6b12..2da3f81 100644
--- a/lib9p/srv_include/lib9p/srv.h
+++ b/lib9p/srv_include/lib9p/srv.h
@@ -46,57 +46,28 @@ struct lib9p_srv_ctx {
struct lib9p_ctx basectx;
struct lib9p_srv_userid *user;
+ BEGIN_PRIVATE(LIB9P_SRV_H);
_errnum err_num;
[[gnu::nonstring]] char err_msg[CONFIG_9P_SRV_MAX_ERR_SIZE];
-
- BEGIN_PRIVATE(LIB9P_SRV_H);
struct _lib9p_srv_sess *parent_sess;
lib9p_tag_t tag;
uint8_t *net_bytes;
- _lib9p_srv_flush_ch_t flush_ch;
- bool flush_acknowledged;
+ _lib9p_srv_flush_ch_t flush_ch; /* flushers for this req _read_ from here */
bool responded;
END_PRIVATE(LIB9P_SRV_H);
};
-void lib9p_ctx_clear_error(struct lib9p_srv_ctx *ctx);
-
-bool lib9p_ctx_has_error(struct lib9p_srv_ctx *ctx);
-
-/** Write a <libmisc/fmt.h>-style error into ctx, return -1. */
-#define lib9p_error(ctx, libmisc_errno, ...) ({ \
- if (!lib9p_ctx_has_error(ctx)) { \
- (ctx)->err_num = libmisc_errno; \
- struct fmt_buf _w = { \
- .dat = (ctx)->err_msg, \
- .cap = sizeof((ctx)->err_msg), \
- }; \
- lo_interface fmt_dest w = LO_BOX(fmt_dest, &_w); \
- fmt_print(w, __VA_ARGS__); \
- if (_w.len < _w.cap) \
- memset(_w.dat + _w.len, 0, _w.cap - _w.len); \
- } \
- -1; \
-})
-
/**
* Return whether there is an outstanding Tflush or Tversion
* cancellation of this request. After becoming true, this may go
* back to false if the Tflush itself is flushed.
+ *
+ * As a special case, returning E_POSIX_ECANCELED indicates that the
+ * flush has been observed, and a Rerror should not be sent ot the
+ * client.
*/
bool lib9p_srv_flush_requested(struct lib9p_srv_ctx *ctx);
-/**
- * Acknowledge that the handler is responding to an outstanding flush;
- * a non-Rerror R-message will be elided in favor of Rflush/Rversion.
- * lib9p_srv_flush_requested() must be true; so do not cr_yield()
- * between checking lib9p_srv_flush_requested() and calling
- * lib9p_srv_acknowledge_flush(). These are separate calls to
- * facilitate cases where a flush merely truncates a call, instead of
- * totally canceling it.
- */
-void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx);
-
/* version-independent stat ***************************************************/
struct lib9p_srv_stat {
@@ -123,18 +94,22 @@ struct lib9p_srv_stat {
struct lib9p_s extension;
#endif
};
+typedef struct lib9p_srv_stat lib9p_srv_stat;
+DECLARE_ERROR_OR(lib9p_srv_stat);
void lib9p_srv_stat_assert(struct lib9p_srv_stat stat);
/* interface definitions ******************************************************/
+typedef struct iovec iovec;
+DECLARE_ERROR_OR(iovec);
+
struct lib9p_srv_dirent {
struct lib9p_qid qid;
struct lib9p_s name;
};
-
-lo_interface lib9p_srv_fio;
-lo_interface lib9p_srv_dio;
+typedef struct lib9p_srv_dirent lib9p_srv_dirent;
+DECLARE_ERROR_OR(lib9p_srv_dirent);
/* FIXME: I don't like that the pointer returned by pread() has to
* remain live after it returns. Perhaps a `respond()`-callback? But
@@ -142,6 +117,46 @@ lo_interface lib9p_srv_dio;
*
* FIXME: It would be nice if pread() could return more than 1 iovec.
*/
+#define lib9p_srv_fio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ LO_FUNC(uint32_t , iounit ) \
+ LO_FUNC(iovec_or_error , pread , struct lib9p_srv_ctx *, \
+ uint32_t byte_count, \
+ uint64_t byte_offset) \
+ /** \
+ * If the file was append-only when fopen()ed, then byte_offset will \
+ * always be 0. \
+ */ \
+ LO_FUNC(uint32_t_or_error , pwrite , struct lib9p_srv_ctx *, \
+ void *buf, \
+ uint32_t byte_count, \
+ uint64_t byte_offset)
+LO_INTERFACE(lib9p_srv_fio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+typedef lo_interface lib9p_srv_fio lib9p_srv_fio;
+DECLARE_ERROR_OR(lib9p_srv_fio);
+
+#define lib9p_srv_dio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
+ LO_FUNC(struct lib9p_qid , qid ) \
+ LO_FUNC(void , iofree ) \
+ /** \
+ * Return the idx-th dirent. idx will always be either 0 or \
+ * prev_idx+1. A dirent with an empty name signals EOF. The string \
+ * must remain valid until the next dread() call or iofree(). \
+ */ \
+ LO_FUNC(lib9p_srv_dirent_or_error , dread , struct lib9p_srv_ctx *, \
+ size_t idx)
+LO_INTERFACE(lib9p_srv_dio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
+typedef lo_interface lib9p_srv_dio lib9p_srv_dio;
+DECLARE_ERROR_OR(lib9p_srv_dio);
+
+struct _lo_lib9p_srv_file_vtable;
+lo_interface lib9p_srv_file {
+ void *self;
+ const struct _lo_lib9p_srv_file_vtable *vtable;
+};
+typedef lo_interface lib9p_srv_file lib9p_srv_file;
+DECLARE_ERROR_OR(lib9p_srv_file);
#define lib9p_srv_file_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
/* resource management **********************************************/ \
\
@@ -167,16 +182,16 @@ lo_interface lib9p_srv_dio;
/* non-"opened" generic I/O *****************************************/ \
\
/** Strings returned from stat() must remain valid until free(). */ \
- LO_FUNC(struct lib9p_srv_stat , stat , struct lib9p_srv_ctx *) \
- LO_FUNC(void , wstat , struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_stat_or_error , stat , struct lib9p_srv_ctx *) \
+ LO_FUNC(error , wstat , struct lib9p_srv_ctx *, \
struct lib9p_srv_stat) \
- LO_FUNC(void , remove , struct lib9p_srv_ctx *) \
+ LO_FUNC(error , remove , struct lib9p_srv_ctx *) \
\
/* non-"opened" directory I/O ***************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_file, dwalk , struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_file_or_error , dwalk , struct lib9p_srv_ctx *, \
struct lib9p_s childname) \
- LO_FUNC(lo_interface lib9p_srv_file, dcreate, struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_file_or_error , dcreate, struct lib9p_srv_ctx *, \
struct lib9p_s childname, \
struct lib9p_srv_userid *user, \
struct lib9p_srv_userid *group, \
@@ -184,50 +199,22 @@ lo_interface lib9p_srv_dio;
\
/* open() for I/O ***************************************************/ \
\
- LO_FUNC(lo_interface lib9p_srv_fio , fopen , struct lib9p_srv_ctx *, \
+ LO_FUNC(lib9p_srv_fio_or_error , fopen , struct lib9p_srv_ctx *, \
bool rd, bool wr, \
bool trunc) \
- LO_FUNC(lo_interface lib9p_srv_dio , dopen , struct lib9p_srv_ctx *)
+ LO_FUNC(lib9p_srv_dio_or_error , dopen , struct lib9p_srv_ctx *)
LO_INTERFACE(lib9p_srv_file); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-#define lib9p_srv_fio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
- LO_FUNC(struct lib9p_qid , qid ) \
- LO_FUNC(void , iofree ) \
- LO_FUNC(uint32_t , iounit ) \
- LO_FUNC(void , pread , struct lib9p_srv_ctx *, \
- uint32_t byte_count, \
- uint64_t byte_offset, \
- struct iovec *ret) \
- /** \
- * If the file was append-only when fopen()ed, then byte_offset will \
- * always be 0. \
- */ \
- LO_FUNC(uint32_t , pwrite , struct lib9p_srv_ctx *, \
- void *buf, \
- uint32_t byte_count, \
- uint64_t byte_offset)
-LO_INTERFACE(lib9p_srv_fio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
-#define lib9p_srv_dio_LO_IFACE /*<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ \
- LO_FUNC(struct lib9p_qid , qid ) \
- LO_FUNC(void , iofree ) \
- /** \
- * Return the idx-th dirent. idx will always be either 0 or \
- * prev_idx+1. A dirent with an empty name signals EOF. The string \
- * must remain valid until the next dread() call or iofree(). \
- */ \
- LO_FUNC(struct lib9p_srv_dirent , dread , struct lib9p_srv_ctx *, \
- size_t idx)
-LO_INTERFACE(lib9p_srv_dio); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
-
#define LIB9P_SRV_NOTDIR(TYP, NAM) \
- static lo_interface lib9p_srv_file NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
- static lo_interface lib9p_srv_file NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, \
- struct lib9p_srv_userid *, struct lib9p_srv_userid *, lib9p_dm_t) { assert_notreached("not a directory"); } \
- static lo_interface lib9p_srv_dio NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); }
+ static lib9p_srv_file_or_error NAM##_dwalk (TYP *, struct lib9p_srv_ctx *, struct lib9p_s) { assert_notreached("not a directory"); } \
+ static lib9p_srv_file_or_error NAM##_dcreate(TYP *, struct lib9p_srv_ctx *, struct lib9p_s, \
+ struct lib9p_srv_userid *, struct lib9p_srv_userid *, lib9p_dm_t) { assert_notreached("not a directory"); } \
+ static lib9p_srv_dio_or_error NAM##_dopen (TYP *, struct lib9p_srv_ctx *) { assert_notreached("not a directory"); } \
+ LM_FORCE_SEMICOLON
#define LIB9P_SRV_NOTFILE(TYP, NAM) \
- static lo_interface lib9p_srv_fio NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); }
+ static lib9p_srv_fio_or_error NAM##_fopen (TYP *, struct lib9p_srv_ctx *, bool, bool, bool) { assert_notreached("not a file"); } \
+ LM_FORCE_SEMICOLON
/* main server entrypoints ****************************************************/
@@ -243,9 +230,9 @@ LO_INTERFACE(net_stream_conn_unix);
struct lib9p_srv {
/* Things you provide */
- void /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */
- lo_interface lib9p_srv_file (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename);
- void (*msglog )(struct lib9p_srv_ctx *, enum lib9p_msg_type, void *hostmsg); /* optional */
+ error /*TODO*/ (*auth )(struct lib9p_srv_ctx *, struct lib9p_s treename); /* optional */
+ lib9p_srv_file_or_error (*rootdir)(struct lib9p_srv_ctx *, struct lib9p_s treename);
+ void (*msglog )(struct lib9p_srv_ctx *, enum lib9p_msg_type, void *hostmsg); /* optional */
#if CONFIG_9P_ENABLE_9P2000_p9p
lo_interface net_stream_conn_unix (*type_assert_unix)(lo_interface net_stream_conn); /* optional */
#endif
diff --git a/lib9p/tests/test_server/fs_flush.c b/lib9p/tests/test_server/fs_flush.c
index eef9891..63a52af 100644
--- a/lib9p/tests/test_server/fs_flush.c
+++ b/lib9p/tests/test_server/fs_flush.c
@@ -31,10 +31,10 @@ static struct lib9p_qid flush_file_qid(struct flush_file *self) {
};
}
-static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error flush_file_stat(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = flush_file_qid(self),
.mode = 0444,
.atime_sec = UTIL9P_ATIME,
@@ -45,29 +45,29 @@ static struct lib9p_srv_stat flush_file_stat(struct flush_file *self, struct lib
.owner_gid = { .name = lib9p_str("root"), .num = 0 },
.last_modifier_uid = { .name = lib9p_str("root"), .num = 0 },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+static error flush_file_wstat(struct flush_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot wstat API file");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
+static error flush_file_remove(struct flush_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot remove API file");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct flush_file, flush_file)
+LIB9P_SRV_NOTDIR(struct flush_file, flush_file);
-static lo_interface lib9p_srv_fio flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+static lib9p_srv_fio_or_error flush_file_fopen(struct flush_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
assert(self);
assert(ctx);
struct flush_fio *ret = heap_alloc(1, struct flush_fio);
ret->parent = self;
- return LO_BOX(lib9p_srv_fio, ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -87,19 +87,17 @@ static uint32_t flush_fio_iounit(struct flush_fio *self) {
return 0;
}
-static uint32_t flush_fio_pwrite(struct flush_fio *LM_UNUSED(self),
+static uint32_t_or_error flush_fio_pwrite(struct flush_fio *LM_UNUSED(self),
struct lib9p_srv_ctx *LM_UNUSED(ctx),
void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
uint64_t LM_UNUSED(offset)) {
assert_notreached("not writable");
}
-static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t LM_UNUSED(byte_offset),
- struct iovec *ret) {
+static iovec_or_error flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t LM_UNUSED(byte_offset)) {
assert(self);
assert(ctx);
- assert(ret);
/* Wait for first Tflush */
while (!lib9p_srv_flush_requested(ctx))
@@ -111,21 +109,21 @@ static void flush_fio_pread(struct flush_fio *self, struct lib9p_srv_ctx *ctx,
while (cr_chan_num_waiters(&ctx->flush_ch) != self->parent->flush_cnt)
cr_yield();
+ /* Yield one more time, just because. */
+ cr_yield();
+
/* Return */
switch (self->parent->flush_behavior) {
case FLUSH_READ:
- *ret = (struct iovec){
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
.iov_base = "Sloth\n",
.iov_len = 6 < byte_count ? 6 : byte_count,
- };
- break;
+ }));
case FLUSH_ERROR:
- lib9p_srv_acknowledge_flush(ctx);
- lib9p_error(ctx, E_POSIX_ECANCELED, "request canceled by flush");
- break;
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EAGAIN, "request canceled by flush"));
case FLUSH_SILENT:
- lib9p_srv_acknowledge_flush(ctx);
- break;
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_ECANCELED, "request canceled by flush"));
+ default:
+ assert_notreached("invalid flush_behavior");
}
- cr_yield();
}
diff --git a/lib9p/tests/test_server/fs_shutdown.c b/lib9p/tests/test_server/fs_shutdown.c
index 5b3bc71..079442e 100644
--- a/lib9p/tests/test_server/fs_shutdown.c
+++ b/lib9p/tests/test_server/fs_shutdown.c
@@ -30,10 +30,10 @@ static struct lib9p_qid shutdown_file_qid(struct shutdown_file *self) {
};
}
-static struct lib9p_srv_stat shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error shutdown_file_stat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = shutdown_file_qid(self),
.mode = 0222 | LIB9P_DM_APPEND,
.atime_sec = UTIL9P_ATIME,
@@ -44,29 +44,29 @@ static struct lib9p_srv_stat shutdown_file_stat(struct shutdown_file *self, stru
.owner_gid = { .name=lib9p_str("root"), .num=0 },
.last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+static error shutdown_file_wstat(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot wstat API file");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
+static error shutdown_file_remove(struct shutdown_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot remove API file");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file)
+LIB9P_SRV_NOTDIR(struct shutdown_file, shutdown_file);
-static lo_interface lib9p_srv_fio shutdown_file_fopen(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+static lib9p_srv_fio_or_error shutdown_file_fopen(struct shutdown_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
assert(self);
assert(ctx);
struct shutdown_fio *ret = heap_alloc(1, struct shutdown_fio);
ret->parent = self;
- return LO_BOX(lib9p_srv_fio, ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -86,19 +86,18 @@ static uint32_t shutdown_fio_iounit(struct shutdown_fio *self) {
return 0;
}
-static uint32_t shutdown_fio_pwrite(struct shutdown_fio *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t offset) {
+static uint32_t_or_error shutdown_fio_pwrite(struct shutdown_fio *self, struct lib9p_srv_ctx *ctx, void *buf, uint32_t byte_count, uint64_t offset) {
assert(self);
assert(ctx);
assert(buf);
assert(offset == 0);
if (byte_count == 0)
- return 0;
+ return ERROR_NEW_VAL(uint32_t, 0);
for (size_t i = 0; i < self->parent->nlisteners; i++)
LO_CALL(LO_BOX(net_stream_listener, &self->parent->listeners[i]), close);
- return byte_count;
+ return ERROR_NEW_VAL(uint32_t, byte_count);
}
-static void shutdown_fio_pread(struct shutdown_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
- uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset),
- struct iovec *LM_UNUSED(ret)) {
+static iovec_or_error shutdown_fio_pread(struct shutdown_fio *LM_UNUSED(self), struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ uint32_t LM_UNUSED(byte_count), uint64_t LM_UNUSED(byte_offset)) {
assert_notreached("not readable");
}
diff --git a/lib9p/tests/test_server/fs_whoami.c b/lib9p/tests/test_server/fs_whoami.c
index 14dd0ba..3cc0683 100644
--- a/lib9p/tests/test_server/fs_whoami.c
+++ b/lib9p/tests/test_server/fs_whoami.c
@@ -53,11 +53,11 @@ static struct lib9p_qid whoami_file_qid(struct whoami_file *self) {
};
}
-static struct lib9p_srv_stat whoami_file_stat(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error whoami_file_stat(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = whoami_file_qid(self),
.mode = 0444,
.atime_sec = UTIL9P_ATIME,
@@ -68,22 +68,22 @@ static struct lib9p_srv_stat whoami_file_stat(struct whoami_file *self, struct l
.owner_gid = { .name=lib9p_str("root"), .num=0 },
.last_modifier_uid = { .name=lib9p_str("root"), .num=0 },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
+static error whoami_file_wstat(struct whoami_file *self, struct lib9p_srv_ctx *ctx, struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot wstat API file");
+ return error_new(E_POSIX_EROFS, "cannot wstat API file");
}
-static void whoami_file_remove(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
+static error whoami_file_remove(struct whoami_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "cannot remove API file");
+ return error_new(E_POSIX_EROFS, "cannot remove API file");
}
-LIB9P_SRV_NOTDIR(struct whoami_file, whoami_file)
+LIB9P_SRV_NOTDIR(struct whoami_file, whoami_file);
-static lo_interface lib9p_srv_fio whoami_file_fopen(struct whoami_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
+static lib9p_srv_fio_or_error whoami_file_fopen(struct whoami_file *self, struct lib9p_srv_ctx *ctx, bool, bool, bool) {
assert(self);
assert(ctx);
@@ -92,7 +92,7 @@ static lo_interface lib9p_srv_fio whoami_file_fopen(struct whoami_file *self, st
ret->buf_len = 0;
ret->buf = NULL;
- return LO_BOX(lib9p_srv_fio, ret);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, ret));
}
/* srv_fio ********************************************************************/
@@ -115,18 +115,16 @@ static uint32_t whoami_fio_iounit(struct whoami_fio *self) {
return 0;
}
-static uint32_t whoami_fio_pwrite(struct whoami_fio *LM_UNUSED(self),
- struct lib9p_srv_ctx *LM_UNUSED(ctx),
- void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(offset)) {
+static uint32_t_or_error whoami_fio_pwrite(struct whoami_fio *LM_UNUSED(self),
+ struct lib9p_srv_ctx *LM_UNUSED(ctx),
+ void *LM_UNUSED(buf), uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(offset)) {
assert_notreached("not writable");
}
-static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
+static iovec_or_error whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t byte_offset) {
assert(self);
assert(ctx);
- assert(ret);
size_t data_size = whoami_len(ctx);
if (self->buf_len < data_size+1) {
@@ -136,18 +134,16 @@ static void whoami_fio_pread(struct whoami_fio *self, struct lib9p_srv_ctx *ctx,
snprintf(self->buf, self->buf_len, "%"PRIu32" %.*s\n",
ctx->user->num, ctx->user->name.len, ctx->user->name.utf8);
- if (byte_offset > (uint64_t)data_size) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is past end-of-file length");
- return;
- }
+ if (byte_offset > (uint64_t)data_size)
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EINVAL, "offset is past end-of-file length"));
size_t beg_off = (size_t)byte_offset;
size_t end_off = beg_off + (size_t)byte_count;
if (end_off > data_size)
end_off = data_size;
- *ret = (struct iovec){
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
.iov_base = &self->buf[beg_off],
.iov_len = end_off-beg_off,
- };
+ }));
}
diff --git a/lib9p/tests/test_server/main.c b/lib9p/tests/test_server/main.c
index 6c7dc1c..0431c40 100644
--- a/lib9p/tests/test_server/main.c
+++ b/lib9p/tests/test_server/main.c
@@ -39,7 +39,7 @@
/* globals ********************************************************************/
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *, struct lib9p_s);
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *, struct lib9p_s);
static const char *hexdig = "0123456789abcdef";
@@ -87,8 +87,8 @@ static struct lib9p_srv_file root =
API_FILE(13, "flush-slowread", flush, .flush_cnt=0, .flush_behavior=FLUSH_READ),
);
-static lo_interface lib9p_srv_file get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
- return root;
+static lib9p_srv_file_or_error get_root(struct lib9p_srv_ctx *LM_UNUSED(ctx), struct lib9p_s LM_UNUSED(treename)) {
+ return ERROR_NEW_VAL(lib9p_srv_file, root);
}
/* main ***********************************************************************/
diff --git a/lib9p/tests/testclient-sess.explog b/lib9p/tests/testclient-sess.explog
index a3838ac..ec8d9c9 100644
--- a/lib9p/tests/testclient-sess.explog
+++ b/lib9p/tests/testclient-sess.explog
@@ -103,7 +103,7 @@
< Ropen { tag=0 qid={ type=(0) vers=1 path=10 } iounit=0 }
> Tread { tag=0 fid=2 offset=0 count=10 }
> Tflush { tag=1 oldtag=0 }
-< Rerror { tag=0 errstr="request canceled by flush" errnum=L_ECANCELED }
+< Rerror { tag=0 errstr="request canceled by flush" errnum=L_EAGAIN }
< Rflush { tag=1 }
# flush, original request is aborted without error
diff --git a/lib9p_util/static.c b/lib9p_util/static.c
index 4354166..6861869 100644
--- a/lib9p_util/static.c
+++ b/lib9p_util/static.c
@@ -33,11 +33,11 @@ static struct lib9p_qid util9p_static_dir_qid(struct util9p_static_dir *self) {
};
}
-static struct lib9p_srv_stat util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error util9p_static_dir_stat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = util9p_static_dir_qid(self),
.mode = LIB9P_DM_DIR | (self->c.perm & 0555),
.atime_sec = self->c.atime,
@@ -48,79 +48,77 @@ static struct lib9p_srv_stat util9p_static_dir_stat(struct util9p_static_dir *se
.owner_gid = { .name = lib9p_str(self->c.g_name), .num = self->c.g_num },
.last_modifier_uid = { .name = lib9p_str(self->c.m_name), .num = self->c.m_num },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_srv_stat) {
+static error util9p_static_dir_wstat(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+static error util9p_static_dir_remove(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static lo_interface lib9p_srv_file util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_s childname) {
+static lib9p_srv_file_or_error util9p_static_dir_dwalk(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_s childname) {
assert(self);
assert(ctx);
for (size_t i = 0; !LO_IS_NULL(self->members[i]); i++) {
lo_interface lib9p_srv_file file = self->members[i];
- struct lib9p_srv_stat stat = LO_CALL(file, stat, ctx);
- if (lib9p_ctx_has_error(ctx))
- break;
- lib9p_srv_stat_assert(stat);
- if (lib9p_str_eq(stat.name, childname))
- return file;
+ lib9p_srv_stat_or_error stat = LO_CALL(file, stat, ctx);
+ if (stat.is_err)
+ return ERROR_NEW_ERR(lib9p_srv_file, stat.err);
+ lib9p_srv_stat_assert(stat.lib9p_srv_stat);
+ if (lib9p_str_eq(stat.lib9p_srv_stat.name, childname))
+ return ERROR_NEW_VAL(lib9p_srv_file, file);
}
- lib9p_error(ctx, E_POSIX_ENOENT, "no such file or directory");
- return LO_NULL(lib9p_srv_file);
+ return ERROR_NEW_ERR(lib9p_srv_file, error_new(E_POSIX_ENOENT, "no such file or directory"));
}
-static lo_interface lib9p_srv_file util9p_static_dir_dcreate(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
- struct lib9p_s LM_UNUSED(childname),
- struct lib9p_srv_userid *LM_UNUSED(user),
- struct lib9p_srv_userid *LM_UNUSED(group),
- lib9p_dm_t LM_UNUSED(perm)) {
+static lib9p_srv_file_or_error util9p_static_dir_dcreate(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx,
+ struct lib9p_s LM_UNUSED(childname),
+ struct lib9p_srv_userid *LM_UNUSED(user),
+ struct lib9p_srv_userid *LM_UNUSED(group),
+ lib9p_dm_t LM_UNUSED(perm)) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
- return LO_NULL(lib9p_srv_file);
+ return ERROR_NEW_ERR(lib9p_srv_file, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
}
LIB9P_SRV_NOTFILE(struct util9p_static_dir, util9p_static_dir);
-static lo_interface lib9p_srv_dio util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_dio_or_error util9p_static_dir_dopen(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return LO_BOX(lib9p_srv_dio, self);
+ return ERROR_NEW_VAL(lib9p_srv_dio, LO_BOX(lib9p_srv_dio, self));
}
static void util9p_static_dir_iofree(struct util9p_static_dir *self) {
assert(self);
}
-static struct lib9p_srv_dirent util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, size_t idx) {
+static lib9p_srv_dirent_or_error util9p_static_dir_dread(struct util9p_static_dir *self, struct lib9p_srv_ctx *ctx, size_t idx) {
assert(self);
assert(ctx);
lo_interface lib9p_srv_file file = self->members[idx];
if (LO_IS_NULL(file))
- return (struct lib9p_srv_dirent){};
+ return ERROR_NEW_VAL(lib9p_srv_dirent, (struct lib9p_srv_dirent){});
- struct lib9p_srv_stat stat = LO_CALL(file, stat, ctx);
- if (lib9p_ctx_has_error(ctx))
- return (struct lib9p_srv_dirent){};
- lib9p_srv_stat_assert(stat);
+ lib9p_srv_stat_or_error stat = LO_CALL(file, stat, ctx);
+ if (stat.is_err)
+ return ERROR_NEW_ERR(lib9p_srv_dirent, stat.err);
+ lib9p_srv_stat_assert(stat.lib9p_srv_stat);
- return (struct lib9p_srv_dirent){
- .qid = stat.qid,
- .name = stat.name,
- };
+ return ERROR_NEW_VAL(lib9p_srv_dirent, ((struct lib9p_srv_dirent){
+ .qid = stat.lib9p_srv_stat.qid,
+ .name = stat.lib9p_srv_stat.name,
+ }));
}
/* file ***********************************************************************/
@@ -150,11 +148,11 @@ static inline size_t util9p_static_file_size(struct util9p_static_file *file) {
}
-static struct lib9p_srv_stat util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
+static lib9p_srv_stat_or_error util9p_static_file_stat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- return (struct lib9p_srv_stat){
+ return ERROR_NEW_VAL(lib9p_srv_stat, ((struct lib9p_srv_stat){
.qid = util9p_static_file_qid(self),
.mode = self->c.perm & 0444,
.atime_sec = self->c.atime,
@@ -165,32 +163,32 @@ static struct lib9p_srv_stat util9p_static_file_stat(struct util9p_static_file *
.owner_gid = { .name = lib9p_str(self->c.g_name), .num = self->c.g_num },
.last_modifier_uid = { .name = lib9p_str(self->c.m_name), .num = self->c.m_num },
.extension = lib9p_str(NULL),
- };
+ }));
}
-static void util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+static error util9p_static_file_wstat(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
struct lib9p_srv_stat) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
-static void util9p_static_file_remove(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
+static error util9p_static_file_remove(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
+ return error_new(E_POSIX_EROFS, "read-only part of filesystem");
}
LIB9P_SRV_NOTDIR(struct util9p_static_file, util9p_static_file);
-static lo_interface lib9p_srv_fio util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- bool rd, bool wr, bool trunc) {
+static lib9p_srv_fio_or_error util9p_static_file_fopen(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ bool rd, bool wr, bool trunc) {
assert(self);
assert(ctx);
assert(rd);
assert(!wr);
assert(!trunc);
- return LO_BOX(lib9p_srv_fio, self);
+ return ERROR_NEW_VAL(lib9p_srv_fio, LO_BOX(lib9p_srv_fio, self));
}
static void util9p_static_file_iofree(struct util9p_static_file *self) {
assert(self);
@@ -199,34 +197,31 @@ static uint32_t util9p_static_file_iounit(struct util9p_static_file *self) {
assert(self);
return 0;
}
-static void util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- uint32_t byte_count, uint64_t byte_offset,
- struct iovec *ret) {
+static iovec_or_error util9p_static_file_pread(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ uint32_t byte_count, uint64_t byte_offset) {
assert(self);
assert(ctx);
- assert(ret);
size_t data_size = util9p_static_file_size(self);
- if (byte_offset > (uint64_t)data_size) {
- lib9p_error(ctx, E_POSIX_EINVAL, "offset is past end-of-file length");
- return;
- }
+ if (byte_offset > (uint64_t)data_size)
+ return ERROR_NEW_ERR(iovec, error_new(E_POSIX_EINVAL, "offset is past end-of-file length"));
size_t beg_off = (size_t)byte_offset;
size_t end_off = beg_off + (size_t)byte_count;
if (end_off > data_size)
end_off = data_size;
- ret->iov_base = &self->data_start[beg_off];
- ret->iov_len = end_off-beg_off;
+ return ERROR_NEW_VAL(iovec, ((struct iovec){
+ .iov_base = &self->data_start[beg_off],
+ .iov_len = end_off-beg_off,
+ }));
}
-static uint32_t util9p_static_file_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
- void *LM_UNUSED(buf),
- uint32_t LM_UNUSED(byte_count),
- uint64_t LM_UNUSED(byte_offset)) {
+static uint32_t_or_error util9p_static_file_pwrite(struct util9p_static_file *self, struct lib9p_srv_ctx *ctx,
+ void *LM_UNUSED(buf),
+ uint32_t LM_UNUSED(byte_count),
+ uint64_t LM_UNUSED(byte_offset)) {
assert(self);
assert(ctx);
- lib9p_error(ctx, E_POSIX_EROFS, "read-only part of filesystem");
- return 0;
+ return ERROR_NEW_ERR(uint32_t, error_new(E_POSIX_EROFS, "read-only part of filesystem"));
}