diff options
-rw-r--r-- | cmd/sbc_harness/fs_harness_flash_bin.c | 66 | ||||
-rw-r--r-- | cmd/sbc_harness/fs_harness_uptime_txt.c | 43 | ||||
-rw-r--r-- | cmd/sbc_harness/main.c | 4 | ||||
-rw-r--r-- | lib9p/srv.c | 121 | ||||
-rw-r--r-- | lib9p/srv_include/lib9p/srv.h | 153 | ||||
-rw-r--r-- | lib9p/tests/test_server/fs_flush.c | 46 | ||||
-rw-r--r-- | lib9p/tests/test_server/fs_shutdown.c | 31 | ||||
-rw-r--r-- | lib9p/tests/test_server/fs_whoami.c | 44 | ||||
-rw-r--r-- | lib9p/tests/test_server/main.c | 6 | ||||
-rw-r--r-- | lib9p/tests/testclient-sess.explog | 2 | ||||
-rw-r--r-- | lib9p_util/static.c | 121 |
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")); } |