diff --git a/Makefile b/Makefile index 2b1487d..c9ca5f6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,9 @@ LIB= 9p SHLIB_MAJOR= 1 -SRCS= lib9p.c connection.c request.c log.c transport/socket.c backend/fs.c +SRCS= pack.c connection.c request.c log.c utils.c transport/socket.c backend/fs.c INCS= lib9p.h fcall.h log.h backend/fs.h CFLAGS= -g -O0 +LIBADD= sbuf + .include diff --git a/backend/fs.c b/backend/fs.c index 84b6b22..34df344 100644 --- a/backend/fs.c +++ b/backend/fs.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -53,6 +54,7 @@ static void fs_wstat(void *, struct l9p_request *); struct fs_softc { const char *fs_rootpath; + bool fs_readonly; }; struct openfile @@ -67,7 +69,7 @@ open_fid(const char *path) { struct openfile *ret; - ret = malloc(sizeof(*ret)); + ret = calloc(1, sizeof(*ret)); ret->fd = -1; ret->name = strdup(path); return (ret); @@ -79,7 +81,7 @@ dostat(struct l9p_stat *s, char *name, struct stat *buf) char *user = getenv("USER"); s->type = 0; s->dev = 0; - s->qid.type = buf->st_mode&S_IFMT; + s->qid.type = buf->st_mode&S_IFMT >> 8; s->qid.path = buf->st_ino; s->qid.version = 0; s->mode = buf->st_mode & 0777; @@ -112,6 +114,19 @@ fs_attach(void *softc, struct l9p_request *req) static void fs_clunk(void *softc, struct l9p_request *req) { + struct l9p_connection *conn = req->lr_conn; + struct openfile *file; + struct stat st; + + file = req->lr_fid->lo_aux; + + if (file->dir) + closedir(file->dir); + else { + close(file->fd); + file->fd = -1; + } + l9p_respond(req, NULL); } @@ -124,12 +139,13 @@ fs_create(void *softc, struct l9p_request *req) static void fs_flush(void *softc, struct l9p_request *req) { - + l9p_respond(req, NULL); } static void fs_open(void *softc, struct l9p_request *req) { + struct l9p_connection *conn = req->lr_conn; struct openfile *file; struct stat st; @@ -142,12 +158,12 @@ fs_open(void *softc, struct l9p_request *req) } else { file->fd = open(file->name, O_RDONLY); if (file->fd < 0) { - l9p_respond(req, "ENOPERM"); + l9p_respond(req, "Permission denied"); return; } } - req->lr_resp.ropen.iounit = 512; + req->lr_resp.ropen.iounit = conn->lc_max_io_size; l9p_respond(req, NULL); } @@ -155,6 +171,7 @@ static void fs_read(void *softc, struct l9p_request *req) { struct openfile *file; + struct l9p_connection *conn = req->lr_conn; struct l9p_stat l9stat; file = req->lr_fid->lo_aux; @@ -163,15 +180,24 @@ fs_read(void *softc, struct l9p_request *req) struct dirent *d; struct stat st; - d = readdir(file->dir); - if (d) { - stat(d->d_name, &st); - dostat(&l9stat, d->d_name, &st); - l9p_pack_stat(req, &l9stat); + for (;;) { + d = readdir(file->dir); + if (d) { + stat(d->d_name, &st); + dostat(&l9stat, d->d_name, &st); + if (l9p_pack_stat(req, &l9stat) != 0) { + seekdir(file->dir, -1); + break; + } + + continue; + } + + break; } } else { - req->lr_resp.io.data = malloc(req->lr_req.io.count); - req->lr_resp.io.count = read(file->fd, req->lr_resp.io.data, req->lr_req.io.count); + size_t niov = l9p_truncate_iov(req->lr_data_iov, req->lr_data_niov, req->lr_req.io.count); + req->lr_resp.io.count = readv(file->fd, req->lr_data_iov, niov); } l9p_respond(req, NULL); @@ -186,7 +212,16 @@ fs_remove(void *softc, struct l9p_request *req) static void fs_stat(void *softc, struct l9p_request *req) { + struct openfile *file; + struct stat st; + struct l9p_stat l9stat; + file = req->lr_fid->lo_aux; + + stat(file->name, &st); + dostat(&req->lr_resp.rstat.stat, file->name, &st); + + l9p_respond(req, NULL); } static void @@ -200,11 +235,11 @@ fs_walk(void *softc, struct l9p_request *req) strcpy(name, file->name); /* build full path. Stat full path. Done */ - for(i=0; i < req->lr_req.twalk.nwname; i++) { + for (i = 0; i < req->lr_req.twalk.nwname; i++) { strcat(name, "/"); strcat(name, req->lr_req.twalk.wname[i]); if (stat(name, &buf) < 0){ - l9p_respond(req, "no such file"); + l9p_respond(req, "No such file or directory"); free(name); return; } diff --git a/connection.c b/connection.c index 8d213cb..bac8343 100644 --- a/connection.c +++ b/connection.c @@ -26,6 +26,8 @@ */ #include +#include +#include #include #include "lib9p.h" #include "log.h" @@ -35,7 +37,7 @@ l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend) { struct l9p_server *server; - server = malloc(sizeof(*server)); + server = calloc(1, sizeof(*server)); server->ls_backend = backend; LIST_INIT(&server->ls_conns); @@ -48,8 +50,11 @@ l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn) { struct l9p_connection *newconn; - newconn = malloc(sizeof(*newconn)); + newconn = calloc(1, sizeof(*newconn)); newconn->lc_server = server; + newconn->lc_msize = L9P_DEFAULT_MSIZE; + LIST_INIT(&newconn->lc_requests); + LIST_INIT(&newconn->lc_files); LIST_INSERT_HEAD(&server->ls_conns, newconn, lc_link); *conn = newconn; @@ -63,29 +68,48 @@ l9p_connection_free(struct l9p_connection *conn) } void -l9p_connection_on_send_request(struct l9p_connection *conn, - void (*cb)(void *, size_t, void *), void *softc) +l9p_connection_on_send_response(struct l9p_connection *conn, + l9p_send_response_t cb, void *aux) { - conn->lc_send_request = cb; - conn->lc_send_request_aux = softc; + conn->lc_send_response = cb; + conn->lc_send_response_aux = aux; } void -l9p_connection_recv(struct l9p_connection *conn, void *buf, size_t len) +l9p_connection_on_get_response_buffer(struct l9p_connection *conn, + l9p_get_response_buffer_t cb, void *aux) +{ + + conn->lc_get_response_buffer = cb; + conn->lc_get_response_buffer_aux = aux; +} + +void +l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov, + const size_t niov, void *aux) { - struct l9p_message msg; struct l9p_request *req; - req = malloc(sizeof(struct l9p_request)); + req = calloc(1, sizeof(struct l9p_request)); + req->lr_aux = aux; req->lr_conn = conn; - msg.lm_buffer = buf; - msg.lm_pos = buf; - msg.lm_end = buf + len; - msg.lm_mode = L9P_UNPACK; - if (l9p_pufcall(&msg, &req->lr_req) != 0) { - l9p_logf(L9P_WARNING, "cannot unpack received message"); + req->lr_req_msg.lm_mode = L9P_UNPACK; + req->lr_req_msg.lm_niov = niov; + memcpy(req->lr_req_msg.lm_iov, iov, sizeof(struct iovec) * niov); + + req->lr_resp_msg.lm_mode = L9P_PACK; + + if (l9p_pufcall(&req->lr_req_msg, &req->lr_req) != 0){ + L9P_LOG(L9P_WARNING, "cannot unpack received message"); + return; + } + + if (conn->lc_get_response_buffer(req, req->lr_resp_msg.lm_iov, + &req->lr_resp_msg.lm_niov, conn->lc_get_response_buffer_aux) != 0) { + L9P_LOG(L9P_WARNING, "cannot obtain buffers for response"); + return; } l9p_dispatch_request(req); @@ -97,6 +121,24 @@ l9p_connection_close(struct l9p_connection *conn) } +struct l9p_openfile * +l9p_connection_alloc_fid(struct l9p_connection *conn, uint32_t fid) +{ + struct l9p_openfile *file; + + if (l9p_connection_find_fid(conn, fid) != NULL) { + errno = EEXIST; + return (NULL); + } + + file = calloc(1, sizeof(struct l9p_openfile)); + file->lo_fid = fid; + file->lo_conn = conn; + LIST_INSERT_HEAD(&conn->lc_files, file, lo_link); + + return (file); +} + struct l9p_openfile * l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid) { @@ -110,6 +152,13 @@ l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid) return (NULL); } +void +l9p_connection_remove_fid(struct l9p_connection *conn, struct l9p_openfile *fid) +{ + + LIST_REMOVE(fid, lo_link); +} + struct l9p_request * l9p_connection_find_tag(struct l9p_connection *conn, uint32_t tag) { diff --git a/fcall.h b/fcall.h index 9117f21..efa49ff 100644 --- a/fcall.h +++ b/fcall.h @@ -193,8 +193,7 @@ struct l9p_f_io struct l9p_f_rstat { struct l9p_hdr hdr; - uint16_t nstat; - uint8_t *stat; + struct l9p_stat stat; }; struct l9p_f_twstat @@ -224,4 +223,4 @@ union l9p_fcall struct l9p_f_io io; }; -#endif //LIB9P_FCALL_H +#endif /* LIB9P_FCALL_H */ diff --git a/lib9p.h b/lib9p.h index cc67a9e..e180b0b 100644 --- a/lib9p.h +++ b/lib9p.h @@ -29,14 +29,28 @@ #ifndef LIB9P_LIB9P_H #define LIB9P_LIB9P_H +#include #include #include +#include +#include #include #include "fcall.h" -#define L9P_ENOFID "FID does not exist" -#define L9P_ENOFUNC "Function not implemented" -#define L9P_EINTR "Interrupted" +#define L9P_DEFAULT_MSIZE 8192 +#define L9P_MAX_IOV 8 + +#define L9P_ENOFID "FID does not exist" +#define L9P_ENOFUNC "Function not implemented" +#define L9P_EINTR "Interrupted" + +struct l9p_request; + +typedef int (l9p_get_response_buffer_t)(struct l9p_request *, + struct iovec *, size_t *, void *); + +typedef int (l9p_send_response_t)(struct l9p_request *, const struct iovec *, + const size_t, const size_t, void *); enum l9p_pack_mode { @@ -52,23 +66,38 @@ enum l9p_integer_type L9P_QWORD = 8 }; +enum l9p_version +{ + L9P_2000 = 1, + L9P_2000U = 2, + L9P_2000L = 3 +}; + struct l9p_message { enum l9p_pack_mode lm_mode; - uint8_t *lm_buffer; - uint8_t *lm_pos; - uint8_t *lm_end; + struct iovec lm_iov[L9P_MAX_IOV]; + size_t lm_niov; + size_t lm_cursor_iov; + size_t lm_cursor_offset; + size_t lm_size; }; struct l9p_request { uint32_t lr_tag; + struct l9p_message lr_req_msg; + struct l9p_message lr_resp_msg; + struct l9p_message lr_readdir_msg; union l9p_fcall lr_req; union l9p_fcall lr_resp; struct l9p_openfile *lr_fid; struct l9p_openfile *lr_newfid; struct l9p_connection *lr_conn; pthread_t lr_thread; + void *lr_aux; + struct iovec lr_data_iov[L9P_MAX_IOV]; + size_t lr_data_niov; LIST_ENTRY(l9p_request) lr_link; }; @@ -85,9 +114,14 @@ struct l9p_openfile struct l9p_connection { struct l9p_server *lc_server; + enum l9p_version lc_version; pthread_mutex_t lc_send_lock; - void (*lc_send_request)(const void *, const size_t, void *); - void *lc_send_request_aux; + uint32_t lc_msize; + uint32_t lc_max_io_size; + l9p_send_response_t *lc_send_response; + l9p_get_response_buffer_t *lc_get_response_buffer; + void *lc_get_response_buffer_aux; + void *lc_send_response_aux; void *lc_softc; LIST_HEAD(, l9p_request) lc_requests; LIST_HEAD(, l9p_openfile) lc_files; @@ -97,6 +131,7 @@ struct l9p_connection struct l9p_server { struct l9p_backend *ls_backend; + enum l9p_version ls_max_version; LIST_HEAD(, l9p_connection) ls_conns; }; @@ -118,19 +153,36 @@ struct l9p_backend }; int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall); -int l9p_fustat(struct l9p_message *msg, struct l9p_stat *s); +int l9p_pustat(struct l9p_message *msg, struct l9p_stat *s); uint16_t l9p_sizeof_stat(struct l9p_stat *stat); int l9p_pack_stat(struct l9p_request *req, struct l9p_stat *s); -int l9p_server_init(struct l9p_server **, struct l9p_backend *backend); +int l9p_server_init(struct l9p_server **serverp, struct l9p_backend *backend); -int l9p_connection_init(struct l9p_server *server, struct l9p_connection **conn); +int l9p_connection_init(struct l9p_server *server, + struct l9p_connection **connp); void l9p_connection_free(struct l9p_connection *conn); -void l9p_connection_on_send_request(struct l9p_connection *conn, void (*cb)(void *, size_t, void *), void *); -void l9p_connection_recv(struct l9p_connection *conn, void *buf, size_t len); +void l9p_connection_on_send_response(struct l9p_connection *conn, + l9p_send_response_t *cb, void *aux); +void l9p_connection_on_get_response_buffer(struct l9p_connection *conn, + l9p_get_response_buffer_t *cb, void *aux); +void l9p_connection_recv(struct l9p_connection *conn, const struct iovec *iov, + size_t niov, void *aux); void l9p_connection_close(struct l9p_connection *conn); -struct l9p_openfile *l9p_connection_find_fid(struct l9p_connection *conn, uint32_t fid); -struct l9p_request *l9p_connection_find_tag(struct l9p_connection *conn, uint32_t tag); +struct l9p_openfile *l9p_connection_alloc_fid(struct l9p_connection *conn, + uint32_t fid); +struct l9p_openfile *l9p_connection_find_fid(struct l9p_connection *conn, + uint32_t fid); +void l9p_connection_remove_fid(struct l9p_connection *conn, + struct l9p_openfile *fid); +struct l9p_request *l9p_connection_find_tag(struct l9p_connection *conn, + uint32_t tag); void l9p_respond(struct l9p_request *req, const char *error); -#endif //LIB9P_LIB9P_H +void l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2, + size_t *niov2, size_t seek); +int l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length); +void l9p_describe_qid(struct l9p_qid *qid, struct sbuf *sb); +void l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version, struct sbuf *sb); + +#endif /* LIB9P_LIB9P_H */ diff --git a/log.c b/log.c index 98cc62d..ff65b3f 100644 --- a/log.c +++ b/log.c @@ -37,12 +37,12 @@ static const char *l9p_log_level_names[] = { }; void -l9p_logf(enum l9p_log_level level, const char *fmt, ...) +l9p_logf(enum l9p_log_level level, const char *func, const char *fmt, ...) { va_list ap; va_start(ap, fmt); - fprintf(stderr, "[%s]\t", l9p_log_level_names[level]); + fprintf(stderr, "[%s]\t %s: ", l9p_log_level_names[level], func); vfprintf(stderr, fmt, ap); fprintf(stderr, "\n"); va_end(ap); diff --git a/log.h b/log.h index 9b3d1fa..cd3eabc 100644 --- a/log.h +++ b/log.h @@ -36,6 +36,8 @@ enum l9p_log_level L9P_ERROR }; -void l9p_logf(enum l9p_log_level level, const char *fmt, ...); +void l9p_logf(enum l9p_log_level level, const char *func, const char *fmt, ...); +#define L9P_LOG(level, fmt, ...) l9p_logf(level, __func__, fmt, ##__VA_ARGS__) + #endif /* LIB9P_LOG_H */ diff --git a/lib9p.c b/pack.c similarity index 55% rename from lib9p.c rename to pack.c index c329bbc..8c06a70 100644 --- a/lib9p.c +++ b/pack.c @@ -31,124 +31,119 @@ #include #include +#include #include +#include +#include #include "lib9p.h" #define N(ary) (sizeof(ary) / sizeof(*ary)) #define STRING_SIZE(s) (L9P_WORD + strlen(s)) #define QID_SIZE (L9P_BYTE + L9P_DWORD + L9P_QWORD) -static void l9p_puint(struct l9p_message *, enum l9p_integer_type, uint32_t *); -static inline void l9p_pu8(struct l9p_message *, uint8_t *); -static inline void l9p_pu16(struct l9p_message *, uint16_t *); -static inline void l9p_pu32(struct l9p_message *, uint32_t *); -static inline void l9p_pu64(struct l9p_message *, uint64_t *); -static void l9p_pustring(struct l9p_message *, char **s); -static void l9p_pustrings(struct l9p_message *, uint16_t *,char *[], size_t); -static void l9p_pudata(struct l9p_message *, uint8_t **, size_t); -static void l9p_puqid(struct l9p_message *, struct l9p_qid *); -static void l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q, +static int l9p_iov_io(struct l9p_message *, void *, size_t); +static int l9p_puint(struct l9p_message *, enum l9p_integer_type, uint32_t *); +static inline int l9p_pu8(struct l9p_message *, uint8_t *); +static inline int l9p_pu16(struct l9p_message *, uint16_t *); +static inline int l9p_pu32(struct l9p_message *, uint32_t *); +static inline int l9p_pu64(struct l9p_message *, uint64_t *); +static int l9p_pustring(struct l9p_message *, char **s); +static int l9p_pustrings(struct l9p_message *, uint16_t *,char *[], size_t); +static int l9p_pudata(struct l9p_message *, uint8_t **, size_t); +static int l9p_puqid(struct l9p_message *, struct l9p_qid *); +static int l9p_puqids(struct l9p_message *, uint16_t *, struct l9p_qid *q, size_t); - -static void -l9p_puint(struct l9p_message *msg, enum l9p_integer_type size, uint32_t *val) +static int +l9p_iov_io(struct l9p_message *msg, void *buffer, size_t len) { - uint8_t *pos; - int v; + size_t done = 0; + size_t left = len; - if(msg->lm_pos + size <= msg->lm_end) { - pos = (uint8_t*)msg->lm_pos; - switch (msg->lm_mode) { - case L9P_PACK: - v = *val; - switch (size) { - case L9P_DWORD: - pos[3] = v>>24; - pos[2] = v>>16; - case L9P_WORD: - pos[1] = v>>8; - case L9P_BYTE: - pos[0] = v; - break; - } - case L9P_UNPACK: - v = 0; - switch (size) { - case L9P_DWORD: - v |= pos[3]<<24; - v |= pos[2]<<16; - case L9P_WORD: - v |= pos[1]<<8; - case L9P_BYTE: - v |= pos[0]; - break; - } - *val = v; + assert(msg != NULL); + assert(buffer != NULL); + + if (len == 0) + return (0); + + if (msg->lm_cursor_iov >= msg->lm_niov) + return (-1); + + while (left > 0) { + size_t idx = msg->lm_cursor_iov; + size_t space = msg->lm_iov[idx].iov_len - msg->lm_cursor_offset; + size_t towrite = MIN(space, left); + + if (msg->lm_mode == L9P_PACK) + memcpy(msg->lm_iov[idx].iov_base + msg->lm_cursor_offset, + buffer + done, towrite); + + if (msg->lm_mode == L9P_UNPACK) + memcpy(buffer + done, msg->lm_iov[idx].iov_base + + msg->lm_cursor_offset, towrite); + + msg->lm_cursor_offset += towrite; + + if (space - towrite == 0) { + /* Advance to next iov */ + msg->lm_cursor_iov++; + msg->lm_cursor_offset = 0; + + if (msg->lm_cursor_iov > msg->lm_niov) + return (-1); } + + done += towrite; + left -= towrite; } - msg->lm_pos += size; + + msg->lm_size += done; + return (done); } -static inline void +static inline int l9p_pu8(struct l9p_message *msg, uint8_t *val) { - uint32_t v; - - v = *val; - l9p_puint(msg, L9P_BYTE, &v); - *val = (uint8_t)v; + return (l9p_iov_io(msg, val, sizeof(uint8_t))); } -static inline void +static inline int l9p_pu16(struct l9p_message *msg, uint16_t *val) { - uint32_t v; - - v = *val; - l9p_puint(msg, L9P_WORD, &v); - *val = (uint16_t)v; + return (l9p_iov_io(msg, val, sizeof(uint16_t))); } -static inline void +static inline int l9p_pu32(struct l9p_message *msg, uint32_t *val) { - l9p_puint(msg, L9P_DWORD, val); + return(l9p_iov_io(msg, val, sizeof(uint32_t))); } -static inline void +static inline int l9p_pu64(struct l9p_message *msg, uint64_t *val) { - uint32_t vl, vb; - - vl = (uint)*val; - vb = (uint)(*val>>32); - l9p_puint(msg, L9P_DWORD, &vl); - l9p_puint(msg, L9P_DWORD, &vb); - *val = vl | ((uint64_t)vb<<32); + return(l9p_iov_io(msg, val, sizeof(uint64_t))); } -static void +static int l9p_pustring(struct l9p_message *msg, char **s) { uint16_t len; - if(msg->lm_mode == L9P_PACK) + if (msg->lm_mode == L9P_PACK) len = strlen(*s); - l9p_pu16(msg, &len); - if (msg->lm_pos + len <= msg->lm_end) { - if (msg->lm_mode == L9P_UNPACK) { - *s = malloc(len + 1); - memcpy(*s, msg->lm_pos, len); - (*s)[len] = '\0'; - } else - memcpy(msg->lm_pos, *s, len); - } - msg->lm_pos += len; + if (l9p_pu16(msg, &len) < 0) + return (-1); + + if (msg->lm_mode == L9P_UNPACK) + *s = calloc(1, len + 1); + + if (l9p_iov_io(msg, *s, len) < 0) + return (-1); } -static void +static int l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[], size_t max) { @@ -157,105 +152,78 @@ l9p_pustrings(struct l9p_message *msg, uint16_t *num, char *strings[], uint16_t len; l9p_pu16(msg, num); - if (*num > max) { - msg->lm_pos = msg->lm_end+1; - return; - } - s = NULL; - - if (msg->lm_mode == L9P_UNPACK) { - s = msg->lm_pos; - size = 0; - for (i = 0; i < *num; i++) { - l9p_pu16(msg, &len); - msg->lm_pos += len; - size += len; - if (msg->lm_pos > msg->lm_end) - return; - } - msg->lm_pos = s; - size += *num; - s = malloc(size); - } - - for (i = 0; i < *num; i++) { - if (msg->lm_mode == L9P_PACK) - len = strlen(strings[i]); - l9p_pu16(msg, &len); - - if (msg->lm_mode == L9P_UNPACK) { - memcpy(s, msg->lm_pos, len); - strings[i] = (char*)s; - s += len; - msg->lm_pos += len; - *s++ = '\0'; - } else - l9p_pudata(msg, &strings[i], len); + for (i = 0; i < MIN(*num, max); i++) { + if (l9p_pustring(msg, &strings[i]) < 0) + return (-1); } } -static void +static int l9p_pudata(struct l9p_message *msg, uint8_t **data, size_t len) { - if (msg->lm_pos + len <= msg->lm_end) { - if (msg->lm_mode == L9P_UNPACK) { - *data = malloc(len); - memcpy(*data, msg->lm_pos, len); - } else - memcpy(msg->lm_pos, *data, len); - } - msg->lm_pos += len; + if (msg->lm_mode == L9P_UNPACK) + *data = malloc(len); + + return (l9p_iov_io(msg, *data, len)); } -static void +static int l9p_puqid(struct l9p_message *msg, struct l9p_qid *qid) { - l9p_pu8(msg, &qid->type); - l9p_pu32(msg, &qid->version); - l9p_pu64(msg, &qid->path); + int r = 0; + + r += l9p_pu8(msg, (uint8_t *)&qid->type); + r += l9p_pu32(msg, &qid->version); + r += l9p_pu64(msg, &qid->path); + + return (r); } -static void +static int l9p_puqids(struct l9p_message *msg, uint16_t *num, struct l9p_qid *qids, size_t max) { int i; l9p_pu16(msg, num); - if (*num > max) { - msg->lm_pos = msg->lm_end + 1; - return; - } - for (i = 0; i < *num; i++) - l9p_puqid(msg, &qids[i]); + for (i = 0; i < *num; i++) { + if (l9p_puqid(msg, &qids[i]) < 0) + return (-1); + } } -void +int l9p_pustat(struct l9p_message *msg, struct l9p_stat *stat) { + int r = 0; uint16_t size; - if(msg->lm_mode == L9P_PACK) + if (msg->lm_mode == L9P_PACK) size = l9p_sizeof_stat(stat) - 2; - l9p_pu16(msg, &size); - l9p_pu16(msg, &stat->type); - l9p_pu32(msg, &stat->dev); - l9p_puqid(msg, &stat->qid); - l9p_pu32(msg, &stat->mode); - l9p_pu32(msg, &stat->atime); - l9p_pu32(msg, &stat->mtime); - l9p_pu64(msg, &stat->length); - l9p_pustring(msg, &stat->name); - l9p_pustring(msg, &stat->uid); - l9p_pustring(msg, &stat->gid); - l9p_pustring(msg, &stat->muid); + r += l9p_pu16(msg, &size); + r += l9p_pu16(msg, &stat->type); + r += l9p_pu32(msg, &stat->dev); + r += l9p_puqid(msg, &stat->qid); + r += l9p_pu32(msg, &stat->mode); + r += l9p_pu32(msg, &stat->atime); + r += l9p_pu32(msg, &stat->mtime); + r += l9p_pu64(msg, &stat->length); + r += l9p_pustring(msg, &stat->name); + r += l9p_pustring(msg, &stat->uid); + r += l9p_pustring(msg, &stat->gid); + r += l9p_pustring(msg, &stat->muid); + + return (r); } int l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall) { + uint32_t length = 0; + + l9p_pu32(msg, &length); l9p_pu8(msg, &fcall->hdr.type); l9p_pu16(msg, &fcall->hdr.tag); @@ -320,13 +288,11 @@ l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall) break; case L9P_RREAD: l9p_pu32(msg, &fcall->io.count); - l9p_pudata(msg, &fcall->io.data, fcall->io.count); break; case L9P_TWRITE: l9p_pu32(msg, &fcall->hdr.fid); l9p_pu64(msg, &fcall->io.offset); l9p_pu32(msg, &fcall->io.count); - l9p_pudata(msg, &fcall->io.data, fcall->io.count); break; case L9P_RWRITE: l9p_pu32(msg, &fcall->io.count); @@ -336,16 +302,33 @@ l9p_pufcall(struct l9p_message *msg, union l9p_fcall *fcall) l9p_pu32(msg, &fcall->hdr.fid); break; case L9P_RSTAT: - l9p_pu16(msg, &fcall->rstat.nstat); - l9p_pudata(msg, (char**)&fcall->rstat.stat, fcall->rstat.nstat); + { + uint16_t size = l9p_sizeof_stat(&fcall->rstat.stat); + l9p_pu16(msg, &size); + l9p_pustat(msg, &fcall->rstat.stat); + } break; - case L9P_TWSTAT: { - uint16_t size; - l9p_pu32(msg, &fcall->hdr.fid); - l9p_pu16(msg, &size); - l9p_pustat(msg, &fcall->twstat.stat); + case L9P_TWSTAT: + { + uint16_t size; + l9p_pu32(msg, &fcall->hdr.fid); + l9p_pu16(msg, &size); + l9p_pustat(msg, &fcall->twstat.stat); + } break; - } + } + + if (msg->lm_mode == L9P_PACK) { + /* Rewind to the beginning */ + uint32_t len = msg->lm_size; + msg->lm_cursor_offset = 0; + msg->lm_cursor_iov = 0; + msg->lm_size -= sizeof(uint32_t); + + if (fcall->hdr.type == L9P_RREAD) + len += fcall->io.count; + + l9p_pu32(msg, &len); } return (0); @@ -358,7 +341,7 @@ l9p_sizeof_stat(struct l9p_stat *stat) { + L9P_DWORD /* dev */ + QID_SIZE /* qid */ + 3 * L9P_DWORD /* mode, atime, mtime */ - + L9P_DWORD /* length */ + + L9P_QWORD /* length */ + STRING_SIZE(stat->name) + STRING_SIZE(stat->uid) + STRING_SIZE(stat->gid) diff --git a/request.c b/request.c index ab8c945..40bb038 100644 --- a/request.c +++ b/request.c @@ -25,8 +25,11 @@ * */ - +#include #include +#include +#include +#include #include "lib9p.h" #include "fcall.h" #include "log.h" @@ -46,7 +49,7 @@ static void l9p_dispatch_twalk(struct l9p_request *req); static void l9p_dispatch_twrite(struct l9p_request *req); static void l9p_dispatch_twstat(struct l9p_request *req); -static struct +static const struct { enum l9p_ftype type; void (*handler)(struct l9p_request *); @@ -65,13 +68,25 @@ static struct {L9P_TWSTAT, l9p_dispatch_twstat} }; +static const char *l9p_versions[] = { + "9P2000", + "9P2000.u", + "9P2000.L" +}; + void l9p_dispatch_request(struct l9p_request *req) { struct l9p_connection *conn = req->lr_conn; + struct sbuf *sb = sbuf_new_auto(); int i; - l9p_logf(L9P_INFO, "new request of type %d", req->lr_req.hdr.type); + l9p_describe_fcall(&req->lr_req, L9P_2000, sb); + sbuf_done(sb); + + L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb)); + sbuf_delete(sb); + req->lr_tag = req->lr_req.hdr.tag; for (i = 0; i < N(l9p_handlers); i++) { @@ -81,6 +96,7 @@ l9p_dispatch_request(struct l9p_request *req) } } + L9P_LOG(L9P_WARNING, "unknown request of type %d", req->lr_req.hdr.type); l9p_respond(req, L9P_ENOFUNC); } @@ -88,19 +104,12 @@ void l9p_respond(struct l9p_request *req, const char *error) { struct l9p_connection *conn = req->lr_conn; - struct l9p_message msg; - void *buf = malloc(1024 * 1024); - - msg.lm_buffer = buf; - msg.lm_pos = buf; - msg.lm_end = buf + (1024 * 1024); - msg.lm_mode = L9P_PACK; + struct sbuf *sb = sbuf_new_auto(); + size_t iosize; switch (req->lr_req.hdr.type) { - case L9P_TVERSION: - break; - - case L9P_TWALK: + case L9P_TCLUNK: + l9p_connection_remove_fid(conn, req->lr_fid); break; } @@ -113,43 +122,66 @@ l9p_respond(struct l9p_request *req, const char *error) req->lr_resp.error.ename = error; } - if (l9p_pufcall(&msg, &req->lr_resp) != 0) { + l9p_describe_fcall(&req->lr_resp, L9P_2000, sb); + sbuf_done(sb); + L9P_LOG(L9P_DEBUG, "%s", sbuf_data(sb)); + sbuf_delete(sb); + + if (l9p_pufcall(&req->lr_resp_msg, &req->lr_resp) != 0) { + L9P_LOG(L9P_ERROR, "cannot pack response"); + return; } - conn->lc_send_request(msg.lm_buffer, msg.lm_pos - msg.lm_buffer, - conn->lc_send_request_aux); + iosize = req->lr_resp_msg.lm_size; + + /* Include I/O size in calculation for Rread response */ + if (req->lr_resp.hdr.type == L9P_RREAD) + iosize += req->lr_resp.io.count; + + conn->lc_send_response(req, req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov, + iosize, conn->lc_send_response_aux); } int l9p_pack_stat(struct l9p_request *req, struct l9p_stat *st) { - struct l9p_message msg; + struct l9p_connection *conn = req->lr_conn; + struct l9p_message *msg = &req->lr_readdir_msg; uint16_t size = l9p_sizeof_stat(st); + if (msg->lm_size == 0) { + /* Initialize message */ + msg->lm_mode = L9P_PACK; + msg->lm_niov = req->lr_data_niov; + memcpy(msg->lm_iov, req->lr_data_iov, sizeof(struct iovec) * req->lr_data_niov); + } + + if (l9p_pustat(msg, st) < 0) + return (-1); + req->lr_resp.io.count += size; - req->lr_resp.io.data = realloc(req->lr_resp.io.data, - req->lr_resp.io.count); - - msg.lm_buffer = req->lr_resp.io.data + req->lr_resp.io.count - size; - msg.lm_pos = req->lr_resp.io.data + req->lr_resp.io.count - size; - msg.lm_end = req->lr_resp.io.data + req->lr_resp.io.count; - msg.lm_mode = L9P_PACK; - - l9p_pustat(&msg, st); + return (0); } static void l9p_dispatch_tversion(struct l9p_request *req) { + struct l9p_connection *conn = req->lr_conn; + enum l9p_version remote_version; + if (!strcmp(req->lr_req.version.version, "9P")) req->lr_resp.version.version = "9P"; else if (!strcmp(req->lr_req.version.version, "9P2000")) req->lr_resp.version.version = "9P2000"; + else if (!strcmp(req->lr_req.version.version, "9P2000.u")) + req->lr_resp.version.version = "9P2000.u"; else req->lr_resp.version.version = "unknown"; - req->lr_resp.version.msize = 8192; + conn->lc_msize = MIN(req->lr_req.version.msize, conn->lc_msize); + conn->lc_max_io_size = conn->lc_msize - 24; + req->lr_resp.version.msize = conn->lc_msize; l9p_respond(req, NULL); } @@ -158,11 +190,7 @@ l9p_dispatch_tattach(struct l9p_request *req) { struct l9p_connection *conn = req->lr_conn; - req->lr_fid = malloc(sizeof(struct l9p_openfile)); - req->lr_fid->lo_fid = req->lr_req.tcreate.hdr.fid; - req->lr_fid->lo_conn = conn; - LIST_INSERT_HEAD(&conn->lc_files, req->lr_fid, lo_link); - + req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.hdr.fid); conn->lc_server->ls_backend->attach(conn->lc_server->ls_backend->softc, req); } @@ -171,13 +199,26 @@ l9p_dispatch_tclunk(struct l9p_request *req) { struct l9p_connection *conn = req->lr_conn; + req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.hdr.fid); + if (!req->lr_fid) { + l9p_respond(req, L9P_ENOFID); + return; + } + conn->lc_server->ls_backend->clunk(conn->lc_server->ls_backend->softc, req); } static void l9p_dispatch_tflush(struct l9p_request *req) { + struct l9p_connection *conn = req->lr_conn; + if (!conn->lc_server->ls_backend->flush) { + l9p_respond(req, L9P_ENOFUNC); + return; + } + + conn->lc_server->ls_backend->flush(conn->lc_server->ls_backend->softc, req); } static void @@ -187,15 +228,11 @@ l9p_dispatch_tcreate(struct l9p_request *req) struct l9p_openfile *fid; if (l9p_connection_find_fid(conn, req->lr_req.tcreate.hdr.fid) != NULL) { - l9p_respond(req, "x"); + l9p_respond(req, L9P_ENOFID); return; } - fid = malloc(sizeof(struct l9p_openfile)); - fid->lo_fid = req->lr_req.tcreate.hdr.fid; - fid->lo_conn = conn; - LIST_INSERT_HEAD(&conn->lc_files, fid, lo_link); - + req->lr_fid = l9p_connection_alloc_fid(conn, req->lr_req.tattach.afid); conn->lc_server->ls_backend->create(conn->lc_server->ls_backend->softc, req); } @@ -231,6 +268,9 @@ l9p_dispatch_tread(struct l9p_request *req) return; } + l9p_seek_iov(req->lr_resp_msg.lm_iov, req->lr_resp_msg.lm_niov, + req->lr_data_iov, &req->lr_data_niov, 11); + conn->lc_server->ls_backend->read(conn->lc_server->ls_backend->softc, req); } @@ -246,7 +286,18 @@ l9p_dispatch_tstat(struct l9p_request *req) struct l9p_connection *conn = req->lr_conn; struct l9p_openfile *fid; + req->lr_fid = l9p_connection_find_fid(conn, req->lr_req.twalk.hdr.fid); + if (!req->lr_fid) { + l9p_respond(req, L9P_ENOFID); + return; + } + if (!conn->lc_server->ls_backend->stat) { + l9p_respond(req, L9P_ENOFUNC); + return; + } + + conn->lc_server->ls_backend->stat(conn->lc_server->ls_backend->softc, req); } static void @@ -262,10 +313,11 @@ l9p_dispatch_twalk(struct l9p_request *req) } if (req->lr_req.twalk.hdr.fid != req->lr_req.twalk.newfid) { - req->lr_newfid = malloc(sizeof(struct l9p_openfile)); - req->lr_newfid->lo_fid = req->lr_req.twalk.newfid; - req->lr_newfid->lo_conn = conn; - LIST_INSERT_HEAD(&conn->lc_files, req->lr_newfid, lo_link); + req->lr_newfid = l9p_connection_alloc_fid(conn, req->lr_req.twalk.newfid); + if (req->lr_newfid == NULL) { + l9p_respond(req, L9P_ENOFID); + return; + } } if (!conn->lc_server->ls_backend->walk) { diff --git a/transport/socket.c b/transport/socket.c index ec2af63..f746288 100644 --- a/transport/socket.c +++ b/transport/socket.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "../lib9p.h" #include "../log.h" @@ -48,7 +49,10 @@ struct l9p_socket_softc }; static int l9p_socket_readmsg(struct l9p_socket_softc *, void **, size_t *); -static void l9p_socket_sendmsg(void *, size_t, void *); +static int l9p_socket_get_response_buffer(struct l9p_request *, + struct iovec *, size_t *, void *); +static int l9p_socket_send_response(struct l9p_request *, const struct iovec *, + const size_t, const size_t, void *); static void *l9p_socket_thread(void *); static int xread(int, void *, size_t); static int xwrite(int, void *, size_t); @@ -105,7 +109,7 @@ l9p_start_server(struct l9p_server *server, const char *host, const char *port) &client_addr_len); if (news < 0) { - l9p_logf(L9P_WARNING, "accept(): %s", strerror(errno)); + L9P_LOG(L9P_WARNING, "accept(): %s", strerror(errno)); continue; } @@ -130,20 +134,22 @@ l9p_socket_accept(struct l9p_server *server, int conn_fd, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); if (err != 0) { - l9p_logf(L9P_WARNING, "cannot look up client name: %s", + L9P_LOG(L9P_WARNING, "cannot look up client name: %s", gai_strerror(err)); } else - l9p_logf(L9P_INFO, "new connection from %s:%s", host, serv); + L9P_LOG(L9P_INFO, "new connection from %s:%s", host, serv); if (l9p_connection_init(server, &conn) != 0) { - l9p_logf(L9P_ERROR, "cannot create new connection"); + L9P_LOG(L9P_ERROR, "cannot create new connection"); + return; } - sc = malloc(sizeof(sc)); + sc = calloc(1, sizeof(sc)); sc->ls_conn = conn; sc->ls_fd = conn_fd; - l9p_connection_on_send_request(conn, l9p_socket_sendmsg, sc); + l9p_connection_on_send_response(conn, l9p_socket_send_response, sc); + l9p_connection_on_get_response_buffer(conn, l9p_socket_get_response_buffer, sc); pthread_create(&sc->ls_thread, NULL, l9p_socket_thread, sc); } @@ -151,6 +157,7 @@ static void * l9p_socket_thread(void *arg) { struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; + struct iovec iov; void *buf; size_t length; @@ -158,10 +165,12 @@ l9p_socket_thread(void *arg) if (l9p_socket_readmsg(sc, &buf, &length) != 0) break; - l9p_connection_recv(sc->ls_conn, buf, length); + iov.iov_base = buf; + iov.iov_len = length; + l9p_connection_recv(sc->ls_conn, &iov, 1, NULL); } - l9p_logf(L9P_INFO, "connection closed"); + L9P_LOG(L9P_INFO, "connection closed"); return (NULL); } @@ -169,46 +178,63 @@ static int l9p_socket_readmsg(struct l9p_socket_softc *sc, void **buf, size_t *size) { uint32_t msize; + uint32_t toread; void *buffer; int fd = sc->ls_fd; - if (xread(fd, &msize, sizeof(uint32_t)) != sizeof(uint32_t)) { - l9p_logf(L9P_ERROR, "short read: %s", strerror(errno)); + buffer = malloc(sizeof(uint32_t)); + + if (xread(fd, buffer, sizeof(uint32_t)) != sizeof(uint32_t)) { + L9P_LOG(L9P_ERROR, "short read: %s", strerror(errno)); return (-1); } - msize -= sizeof(msize); - buffer = malloc(msize); + msize = *(uint32_t *)buffer; + toread = msize - sizeof(uint32_t); + buffer = realloc(buffer, msize); - if (xread(fd, buffer, msize) != msize) { - l9p_logf(L9P_ERROR, "short read: %s", strerror(errno)); + if (xread(fd, buffer + sizeof(uint32_t), toread) != toread) { + L9P_LOG(L9P_ERROR, "short read: %s", strerror(errno)); return (-1); } *size = msize; *buf = buffer; - l9p_logf(L9P_INFO, "%p: read complete message, buf=%p size=%d", sc->ls_conn, buffer, msize); + L9P_LOG(L9P_INFO, "%p: read complete message, buf=%p size=%d", sc->ls_conn, buffer, msize); return (0); } -static void -l9p_socket_sendmsg(void *buf, size_t len, void *arg) +static int +l9p_socket_get_response_buffer(struct l9p_request *req, struct iovec *iov, + size_t *niovp, void *arg) +{ + size_t size = req->lr_conn->lc_msize; + void *buf; + + buf = malloc(size); + iov[0].iov_base = buf; + iov[0].iov_len = size; + + *niovp = 1; + return (0); +} + +static int +l9p_socket_send_response(struct l9p_request *req, const struct iovec *iov, + const size_t niov, const size_t iolen, void *arg) { struct l9p_socket_softc *sc = (struct l9p_socket_softc *)arg; - uint32_t msize = (uint32_t)len + sizeof(uint32_t); - l9p_logf(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg, buf, len); + L9P_LOG(L9P_DEBUG, "%p: sending reply, buf=%p, size=%d", arg, + iov[0].iov_base, iolen); - if (xwrite(sc->ls_fd, &msize, sizeof(uint32_t)) != sizeof(uint32_t)) { - l9p_logf(L9P_ERROR, "short write: %s", strerror(errno)); - return; + if (xwrite(sc->ls_fd, iov[0].iov_base, iolen) != iolen) { + L9_LOG(L9P_ERROR, "short write: %s", strerror(errno)); + return (-1); } - if (xwrite(sc->ls_fd, buf, len) != len) { - l9p_logf(L9P_ERROR, "short write: %s", strerror(errno)); - return; - } + return (0); } static int diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..fa8cf01 --- /dev/null +++ b/utils.c @@ -0,0 +1,249 @@ +/* + * Copyright 2016 Jakub Klama + * All rights reserved + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include "lib9p.h" +#include "fcall.h" + +static const char *ftype_names[] = { + "Tversion", + "Rversion", + "Tauth", + "Rauth", + "Tattach", + "Rattach", + "Terror", + "Rerror", + "Tflush", + "Rflush", + "Twalk", + "Rwalk", + "Topen", + "Ropen", + "Tcreate", + "Rcreate", + "Tread", + "Rread", + "Twrite", + "Rwrite", + "Tclunk", + "Rclunk", + "Tremove", + "Rremove", + "Tstat", + "Rstat", + "Twstat", + "Rwstat" +}; + +void +l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2, + size_t *niov2, size_t seek) +{ + size_t remainder = 0; + size_t left = seek; + int i, j; + + for (i = 0; i < niov1; i++) { + size_t toseek = MIN(left, iov1[i].iov_len); + left -= toseek; + + if (toseek == iov1[i].iov_len) + continue; + + if (left == 0) { + remainder = toseek; + break; + } + } + + for (j = i; j < niov1; j++) { + iov2[j - i].iov_base = iov1[j].iov_base + remainder; + iov2[j - i].iov_len = iov1[j].iov_len - remainder; + remainder = 0; + } + + *niov2 = j - i; +} + +int +l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length) +{ + int i; + size_t done = 0; + + for (i = 0; i < niov; i++) { + size_t toseek = MIN(length - done, iov[i].iov_len); + done += toseek; + + if (toseek < iov[i].iov_len) { + iov[i].iov_len = toseek; + return (i + 1); + } + } + + return (niov); +} + +void +l9p_describe_qid(struct l9p_qid *qid, struct sbuf *sb) +{ + + assert(qid != NULL); + assert(sb != NULL); + + sbuf_printf(sb, "<0x%02x,%u,0x%016llx>", qid->type, qid->version, + qid->path); +} + +void +l9p_describe_stat(struct l9p_stat *st, struct sbuf *sb) +{ + + assert(st != NULL); + assert(sb != NULL); + + sbuf_printf(sb, "type=0x%04x dev=%d name=\"%s\" uid=\"%s\"", + st->type, st->dev, st->name, st->uid); +} + +void +l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version, + struct sbuf *sb) +{ + uint8_t type; + int i; + + assert(fcall != NULL); + assert(sb != NULL); + assert(version <= L9P_2000L && version >= L9P_2000); + + type = fcall->hdr.type; + + if (type < 100 || type > 127) { + sbuf_printf(sb, " tag=%d", type, + fcall->hdr.tag); + return; + } + + sbuf_printf(sb, "%s tag=%d", ftype_names[type - L9P_TVERSION], + fcall->hdr.tag); + + switch (type) { + case L9P_TVERSION: + case L9P_RVERSION: + sbuf_printf(sb, " version=\"%s\" msize=%d", fcall->version.version, + fcall->version.msize); + return; + case L9P_TAUTH: + sbuf_printf(sb, "afid=%d uname=\"%s\" aname=\"%s\"", fcall->hdr.fid, + fcall->tauth.uname, fcall->tauth.aname); + return; + case L9P_TATTACH: + sbuf_printf(sb, " fid=%d afid=%d uname=\"%s\" aname=\"%s\"", + fcall->hdr.fid, fcall->tattach.afid, fcall->tattach.uname, + fcall->tattach.aname); + return; + case L9P_TFLUSH: + sbuf_printf(sb, " oldtag=%d", fcall->tflush.oldtag); + return; + case L9P_TWALK: + sbuf_printf(sb, " fid=%d newfid=%d wname=\"", fcall->hdr.fid, + fcall->twalk.newfid); + + for (i = 0; i < fcall->twalk.nwname; i++) { + sbuf_printf(sb, "%s", fcall->twalk.wname[i]); + if (i != fcall->twalk.nwname - 1) + sbuf_printf(sb, "/"); + } + sbuf_printf(sb, "\""); + return; + case L9P_RWALK: + sbuf_printf(sb, " wqid="); + for (i = 0; i < fcall->rwalk.nwqid; i++) { + l9p_describe_qid(&fcall->rwalk.wqid[i], sb); + if (i != fcall->rwalk.nwqid - 1) + sbuf_printf(sb, ","); + } + + return; + case L9P_TOPEN: + sbuf_printf(sb, " fid=%d mode=%d", fcall->hdr.fid, + fcall->tcreate.mode); + + return; + case L9P_ROPEN: + sbuf_printf(sb, " qid="); + l9p_describe_qid(&fcall->ropen.qid, sb); + sbuf_printf(sb, " iounit=%d", fcall->ropen.iounit); + return; + case L9P_TCREATE: + sbuf_printf(sb, " fid=%d name=\"%s\" perm=0x%08x mode=%d", + fcall->hdr.fid, fcall->tcreate.name, fcall->tcreate.perm, + fcall->tcreate.mode); + return; + case L9P_RCREATE: + return; + case L9P_TREAD: + sbuf_printf(sb, " fid=%d offset=%lu count=%u", fcall->hdr.fid, + fcall->io.offset, fcall->io.count); + return; + + case L9P_RREAD: + case L9P_RWRITE: + sbuf_printf(sb, " count=%d", fcall->io.count); + return; + case L9P_TWRITE: + sbuf_printf(sb, " fid=%d offset=%lu count=%u", fcall->hdr.fid, + fcall->io.offset, fcall->io.count); + return; + case L9P_TCLUNK: + sbuf_printf(sb, " fid=%d ", fcall->hdr.fid); + return; + case L9P_TREMOVE: + sbuf_printf(sb, " fid=%d", fcall->hdr.fid); + return; + case L9P_RREMOVE: + return; + case L9P_TSTAT: + sbuf_printf(sb, " fid=%d", fcall->hdr.fid); + return; + case L9P_RSTAT: + sbuf_printf(sb, " "); + l9p_describe_stat(&fcall->rstat.stat, sb); + return; + case L9P_TWSTAT: + sbuf_printf(sb, " fid=%d", fcall->hdr.fid); + return; + case L9P_RWSTAT: + return; + } + }