1/*
2 * Copyright 2016 Jakub Klama <jceel@FreeBSD.org>
3 * All rights reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted providing that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#include <errno.h>
29#include <stdbool.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <assert.h>
35#include <inttypes.h>
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/uio.h>
39#if defined(__FreeBSD__)
40#include <sys/sbuf.h>
41#else
42#include "sbuf/sbuf.h"
43#endif
44#include "lib9p.h"
45#include "fcall.h"
46#include "linux_errno.h"
47
48#ifdef __APPLE__
49  #define GETGROUPS_GROUP_TYPE_IS_INT
50#endif
51
52#define N(ary)          (sizeof(ary) / sizeof(*ary))
53
54/* See l9p_describe_bits() below. */
55struct descbits {
56	uint64_t	db_mask;	/* mask value */
57	uint64_t	db_match;	/* match value */
58	const char	*db_name;	/* name for matched value */
59};
60
61
62static bool l9p_describe_bits(const char *, uint64_t, const char *,
63    const struct descbits *, struct sbuf *);
64static void l9p_describe_fid(const char *, uint32_t, struct sbuf *);
65static void l9p_describe_mode(const char *, uint32_t, struct sbuf *);
66static void l9p_describe_name(const char *, char *, struct sbuf *);
67static void l9p_describe_perm(const char *, uint32_t, struct sbuf *);
68static void l9p_describe_lperm(const char *, uint32_t, struct sbuf *);
69static void l9p_describe_qid(const char *, struct l9p_qid *, struct sbuf *);
70static void l9p_describe_l9stat(const char *, struct l9p_stat *,
71    enum l9p_version, struct sbuf *);
72static void l9p_describe_statfs(const char *, struct l9p_statfs *,
73    struct sbuf *);
74static void l9p_describe_time(struct sbuf *, const char *, uint64_t, uint64_t);
75static void l9p_describe_readdir(struct sbuf *, struct l9p_f_io *);
76static void l9p_describe_size(const char *, uint64_t, struct sbuf *);
77static void l9p_describe_ugid(const char *, uint32_t, struct sbuf *);
78static void l9p_describe_getattr_mask(uint64_t, struct sbuf *);
79static void l9p_describe_unlinkat_flags(const char *, uint32_t, struct sbuf *);
80static const char *lookup_linux_errno(uint32_t);
81
82/*
83 * Using indexed initializers, we can have these occur in any order.
84 * Using adjacent-string concatenation ("T" #name, "R" #name), we
85 * get both Tfoo and Rfoo strings with one copy of the name.
86 * Alas, there is no stupid cpp trick to lowercase-ify, so we
87 * have to write each name twice.  In which case we might as well
88 * make the second one a string in the first place and not bother
89 * with the stringizing.
90 *
91 * This table should have entries for each enum value in fcall.h.
92 */
93#define X(NAME, name)	[L9P_T##NAME - L9P__FIRST] = "T" name, \
94			[L9P_R##NAME - L9P__FIRST] = "R" name
95static const char *ftype_names[] = {
96	X(VERSION,	"version"),
97	X(AUTH,		"auth"),
98	X(ATTACH,	"attach"),
99	X(ERROR,	"error"),
100	X(LERROR,	"lerror"),
101	X(FLUSH,	"flush"),
102	X(WALK,		"walk"),
103	X(OPEN,		"open"),
104	X(CREATE,	"create"),
105	X(READ,		"read"),
106	X(WRITE,	"write"),
107	X(CLUNK,	"clunk"),
108	X(REMOVE,	"remove"),
109	X(STAT,		"stat"),
110	X(WSTAT,	"wstat"),
111	X(STATFS,	"statfs"),
112	X(LOPEN,	"lopen"),
113	X(LCREATE,	"lcreate"),
114	X(SYMLINK,	"symlink"),
115	X(MKNOD,	"mknod"),
116	X(RENAME,	"rename"),
117	X(READLINK,	"readlink"),
118	X(GETATTR,	"getattr"),
119	X(SETATTR,	"setattr"),
120	X(XATTRWALK,	"xattrwalk"),
121	X(XATTRCREATE,	"xattrcreate"),
122	X(READDIR,	"readdir"),
123	X(FSYNC,	"fsync"),
124	X(LOCK,		"lock"),
125	X(GETLOCK,	"getlock"),
126	X(LINK,		"link"),
127	X(MKDIR,	"mkdir"),
128	X(RENAMEAT,	"renameat"),
129	X(UNLINKAT,	"unlinkat"),
130};
131#undef X
132
133void
134l9p_seek_iov(struct iovec *iov1, size_t niov1, struct iovec *iov2,
135    size_t *niov2, size_t seek)
136{
137	size_t remainder = 0;
138	size_t left = seek;
139	size_t i, j;
140
141	for (i = 0; i < niov1; i++) {
142		size_t toseek = MIN(left, iov1[i].iov_len);
143		left -= toseek;
144
145		if (toseek == iov1[i].iov_len)
146			continue;
147
148		if (left == 0) {
149			remainder = toseek;
150			break;
151		}
152	}
153
154	for (j = i; j < niov1; j++) {
155		iov2[j - i].iov_base = (char *)iov1[j].iov_base + remainder;
156		iov2[j - i].iov_len = iov1[j].iov_len - remainder;
157		remainder = 0;
158	}
159
160	*niov2 = j - i;
161}
162
163size_t
164l9p_truncate_iov(struct iovec *iov, size_t niov, size_t length)
165{
166	size_t i, done = 0;
167
168	for (i = 0; i < niov; i++) {
169		size_t toseek = MIN(length - done, iov[i].iov_len);
170		done += toseek;
171
172		if (toseek < iov[i].iov_len) {
173			iov[i].iov_len = toseek;
174			return (i + 1);
175		}
176	}
177
178	return (niov);
179}
180
181/*
182 * This wrapper for getgrouplist() that malloc'ed memory, and
183 * papers over FreeBSD vs Mac differences in the getgrouplist()
184 * argument types.
185 *
186 * Note that this function guarantees that *either*:
187 *     return value != NULL and *angroups has been set
188 * or: return value == NULL and *angroups is 0
189 */
190gid_t *
191l9p_getgrlist(const char *name, gid_t basegid, int *angroups)
192{
193#ifdef GETGROUPS_GROUP_TYPE_IS_INT
194	int i, *int_groups;
195#endif
196	gid_t *groups;
197	int ngroups;
198
199	/*
200	 * Todo, perhaps: while getgrouplist() returns -1, expand.
201	 * For now just use NGROUPS_MAX.
202	 */
203	ngroups = NGROUPS_MAX;
204	groups = malloc((size_t)ngroups * sizeof(*groups));
205#ifdef GETGROUPS_GROUP_TYPE_IS_INT
206	int_groups = groups ? malloc((size_t)ngroups * sizeof(*int_groups)) :
207	    NULL;
208	if (int_groups == NULL) {
209		free(groups);
210		groups = NULL;
211	}
212#endif
213	if (groups == NULL) {
214		*angroups = 0;
215		return (NULL);
216	}
217#ifdef GETGROUPS_GROUP_TYPE_IS_INT
218	(void) getgrouplist(name, (int)basegid, int_groups, &ngroups);
219	for (i = 0; i < ngroups; i++)
220		groups[i] = (gid_t)int_groups[i];
221#else
222	(void) getgrouplist(name, basegid, groups, &ngroups);
223#endif
224	*angroups = ngroups;
225	return (groups);
226}
227
228/*
229 * For the various debug describe ops: decode bits in a bit-field-y
230 * value.  For example, we might produce:
231 *     value=0x3c[FOO,BAR,QUUX,?0x20]
232 * when FOO is bit 0x10, BAR is 0x08, and QUUX is 0x04 (as defined
233 * by the table).  This leaves 0x20 (bit 5) as a mystery, while bits
234 * 4, 3, and 2 were decoded.  (Bits 0 and 1 were 0 on input hence
235 * were not attempted here.)
236 *
237 * For general use we take a uint64_t <value>.  The bit description
238 * table <db> is an array of {mask, match, str} values ending with
239 * {0, 0, NULL}.
240 *
241 * If <str> is non-NULL we'll print it and the mask as well (if
242 * str is NULL we'll print neither).  The mask is always printed in
243 * hex at the moment.  See undec description too.
244 *
245 * For convenience, you can use a mask-and-match value, e.g., to
246 * decode a 2-bit field in bits 0 and 1 you can mask against 3 and
247 * match the values 0, 1, 2, and 3.  To handle this, make sure that
248 * all masks-with-same-match are sequential.
249 *
250 * If there are any nonzero undecoded bits, print them after
251 * all the decode-able bits have been handled.
252 *
253 * The <oc> argument defines the open and close bracket characters,
254 * typically "[]", that surround the entire string.  If NULL, no
255 * brackets are added, else oc[0] goes in the front and oc[1] at
256 * the end, after printing any <str><value> part.
257 *
258 * Returns true if it printed anything (other than the implied
259 * str-and-value, that is).
260 */
261static bool
262l9p_describe_bits(const char *str, uint64_t value, const char *oc,
263    const struct descbits *db, struct sbuf *sb)
264{
265	const char *sep;
266	char bracketbuf[2] = "";
267	bool printed = false;
268
269	if (str != NULL)
270		sbuf_printf(sb, "%s0x%" PRIx64, str, value);
271
272	if (oc != NULL)
273		bracketbuf[0] = oc[0];
274	sep = bracketbuf;
275	for (; db->db_name != NULL; db++) {
276		if ((value & db->db_mask) == db->db_match) {
277			sbuf_printf(sb, "%s%s", sep, db->db_name);
278			sep = ",";
279			printed = true;
280
281			/*
282			 * Clear the field, and make sure we
283			 * won't match a zero-valued field with
284			 * this same mask.
285			 */
286			value &= ~db->db_mask;
287			while (db[1].db_mask == db->db_mask &&
288			    db[1].db_name != NULL)
289				db++;
290		}
291	}
292	if (value != 0) {
293		sbuf_printf(sb, "%s?0x%" PRIx64, sep, value);
294		printed = true;
295	}
296	if (printed && oc != NULL) {
297		bracketbuf[0] = oc[1];
298		sbuf_cat(sb, bracketbuf);
299	}
300	return (printed);
301}
302
303/*
304 * Show file ID.
305 */
306static void
307l9p_describe_fid(const char *str, uint32_t fid, struct sbuf *sb)
308{
309
310	sbuf_printf(sb, "%s%" PRIu32, str, fid);
311}
312
313/*
314 * Show user or group ID.
315 */
316static void
317l9p_describe_ugid(const char *str, uint32_t ugid, struct sbuf *sb)
318{
319
320	sbuf_printf(sb, "%s%" PRIu32, str, ugid);
321}
322
323/*
324 * Show file mode (O_RDWR, O_RDONLY, etc).  The argument is
325 * an l9p_omode, not a Linux flags mode.  Linux flags are
326 * decoded with l9p_describe_lflags.
327 */
328static void
329l9p_describe_mode(const char *str, uint32_t mode, struct sbuf *sb)
330{
331	static const struct descbits bits[] = {
332		{ L9P_OACCMODE,	L9P_OREAD,	"OREAD" },
333		{ L9P_OACCMODE,	L9P_OWRITE,	"OWRITE" },
334		{ L9P_OACCMODE,	L9P_ORDWR,	"ORDWR" },
335		{ L9P_OACCMODE,	L9P_OEXEC,	"OEXEC" },
336
337		{ L9P_OCEXEC,	L9P_OCEXEC,	"OCEXEC" },
338		{ L9P_ODIRECT,	L9P_ODIRECT,	"ODIRECT" },
339		{ L9P_ORCLOSE,	L9P_ORCLOSE,	"ORCLOSE" },
340		{ L9P_OTRUNC,	L9P_OTRUNC,	"OTRUNC" },
341		{ 0, 0, NULL }
342	};
343
344	(void) l9p_describe_bits(str, mode, "[]", bits, sb);
345}
346
347/*
348 * Show Linux mode/flags.
349 */
350static void
351l9p_describe_lflags(const char *str, uint32_t flags, struct sbuf *sb)
352{
353	static const struct descbits bits[] = {
354	    { L9P_OACCMODE,	L9P_OREAD,		"O_READ" },
355	    { L9P_OACCMODE,	L9P_OWRITE,		"O_WRITE" },
356	    { L9P_OACCMODE,	L9P_ORDWR,		"O_RDWR" },
357	    { L9P_OACCMODE,	L9P_OEXEC,		"O_EXEC" },
358
359	    { L9P_L_O_APPEND,	L9P_L_O_APPEND,		"O_APPEND" },
360	    { L9P_L_O_CLOEXEC,	L9P_L_O_CLOEXEC,	"O_CLOEXEC" },
361	    { L9P_L_O_CREAT,	L9P_L_O_CREAT,		"O_CREAT" },
362	    { L9P_L_O_DIRECT,	L9P_L_O_DIRECT,		"O_DIRECT" },
363	    { L9P_L_O_DIRECTORY, L9P_L_O_DIRECTORY,	"O_DIRECTORY" },
364	    { L9P_L_O_DSYNC,	L9P_L_O_DSYNC,		"O_DSYNC" },
365	    { L9P_L_O_EXCL,	L9P_L_O_EXCL,		"O_EXCL" },
366	    { L9P_L_O_FASYNC,	L9P_L_O_FASYNC,		"O_FASYNC" },
367	    { L9P_L_O_LARGEFILE, L9P_L_O_LARGEFILE,	"O_LARGEFILE" },
368	    { L9P_L_O_NOATIME,	L9P_L_O_NOATIME,	"O_NOATIME" },
369	    { L9P_L_O_NOCTTY,	L9P_L_O_NOCTTY,		"O_NOCTTY" },
370	    { L9P_L_O_NOFOLLOW,	L9P_L_O_NOFOLLOW,	"O_NOFOLLOW" },
371	    { L9P_L_O_NONBLOCK,	L9P_L_O_NONBLOCK,	"O_NONBLOCK" },
372	    { L9P_L_O_PATH,	L9P_L_O_PATH,		"O_PATH" },
373	    { L9P_L_O_SYNC,	L9P_L_O_SYNC,		"O_SYNC" },
374	    { L9P_L_O_TMPFILE,	L9P_L_O_TMPFILE,	"O_TMPFILE" },
375	    { L9P_L_O_TMPFILE,	L9P_L_O_TMPFILE,	"O_TMPFILE" },
376	    { L9P_L_O_TRUNC,	L9P_L_O_TRUNC,		"O_TRUNC" },
377	    { 0, 0, NULL }
378	};
379
380	(void) l9p_describe_bits(str, flags, "[]", bits, sb);
381}
382
383/*
384 * Show file name or other similar, potentially-very-long string.
385 * Actual strings get quotes, a NULL name (if it occurs) gets
386 * <null> (no quotes), so you can tell the difference.
387 */
388static void
389l9p_describe_name(const char *str, char *name, struct sbuf *sb)
390{
391	size_t len;
392
393	if (name == NULL) {
394		sbuf_printf(sb, "%s<null>", str);
395		return;
396	}
397
398	len = strlen(name);
399
400	if (len > 32)
401		sbuf_printf(sb, "%s\"%.*s...\"", str, 32 - 3, name);
402	else
403		sbuf_printf(sb, "%s\"%.*s\"", str, (int)len, name);
404}
405
406/*
407 * Show permissions (rwx etc).  Prints the value in hex only if
408 * the rwx bits do not cover the entire value.
409 */
410static void
411l9p_describe_perm(const char *str, uint32_t mode, struct sbuf *sb)
412{
413	char pbuf[12];
414
415	strmode(mode & 0777, pbuf);
416	if ((mode & ~(uint32_t)0777) != 0)
417		sbuf_printf(sb, "%s0x%" PRIx32 "<%.9s>", str, mode, pbuf + 1);
418	else
419		sbuf_printf(sb, "%s<%.9s>", str, pbuf + 1);
420}
421
422/*
423 * Show "extended" permissions: regular permissions, but also the
424 * various DM* extension bits from 9P2000.u.
425 */
426static void
427l9p_describe_ext_perm(const char *str, uint32_t mode, struct sbuf *sb)
428{
429	static const struct descbits bits[] = {
430		{ L9P_DMDIR,	L9P_DMDIR,	"DMDIR" },
431		{ L9P_DMAPPEND,	L9P_DMAPPEND,	"DMAPPEND" },
432		{ L9P_DMEXCL,	L9P_DMEXCL,	"DMEXCL" },
433		{ L9P_DMMOUNT,	L9P_DMMOUNT,	"DMMOUNT" },
434		{ L9P_DMAUTH,	L9P_DMAUTH,	"DMAUTH" },
435		{ L9P_DMTMP,	L9P_DMTMP,	"DMTMP" },
436		{ L9P_DMSYMLINK, L9P_DMSYMLINK,	"DMSYMLINK" },
437		{ L9P_DMDEVICE,	L9P_DMDEVICE,	"DMDEVICE" },
438		{ L9P_DMNAMEDPIPE, L9P_DMNAMEDPIPE, "DMNAMEDPIPE" },
439		{ L9P_DMSOCKET,	L9P_DMSOCKET,	"DMSOCKET" },
440		{ L9P_DMSETUID,	L9P_DMSETUID,	"DMSETUID" },
441		{ L9P_DMSETGID,	L9P_DMSETGID,	"DMSETGID" },
442		{ 0, 0, NULL }
443	};
444	bool need_sep;
445
446	sbuf_printf(sb, "%s[", str);
447	need_sep = l9p_describe_bits(NULL, mode & ~(uint32_t)0777, NULL,
448	    bits, sb);
449	l9p_describe_perm(need_sep ? "," : "", mode & 0777, sb);
450	sbuf_cat(sb, "]");
451}
452
453/*
454 * Show Linux-specific permissions: regular permissions, but also
455 * the S_IFMT field.
456 */
457static void
458l9p_describe_lperm(const char *str, uint32_t mode, struct sbuf *sb)
459{
460	static const struct descbits bits[] = {
461		{ S_IFMT,	S_IFIFO,	"S_IFIFO" },
462		{ S_IFMT,	S_IFCHR,	"S_IFCHR" },
463		{ S_IFMT,	S_IFDIR,	"S_IFDIR" },
464		{ S_IFMT,	S_IFBLK,	"S_IFBLK" },
465		{ S_IFMT,	S_IFREG,	"S_IFREG" },
466		{ S_IFMT,	S_IFLNK,	"S_IFLNK" },
467		{ S_IFMT,	S_IFSOCK,	"S_IFSOCK" },
468		{ 0, 0, NULL }
469	};
470	bool need_sep;
471
472	sbuf_printf(sb, "%s[", str);
473	need_sep = l9p_describe_bits(NULL, mode & ~(uint32_t)0777, NULL,
474	    bits, sb);
475	l9p_describe_perm(need_sep ? "," : "", mode & 0777, sb);
476	sbuf_cat(sb, "]");
477}
478
479/*
480 * Show qid (<type, version, path> tuple).
481 */
482static void
483l9p_describe_qid(const char *str, struct l9p_qid *qid, struct sbuf *sb)
484{
485	static const struct descbits bits[] = {
486		/*
487		 * NB: L9P_QTFILE is 0, i.e., is implied by no
488		 * other bits being set.  We get this produced
489		 * when we mask against 0xff and compare for
490		 * L9P_QTFILE, but we must do it first so that
491		 * we mask against the original (not-adjusted)
492		 * value.
493		 */
494		{ 0xff,		L9P_QTFILE,	"FILE" },
495		{ L9P_QTDIR,	L9P_QTDIR,	"DIR" },
496		{ L9P_QTAPPEND,	L9P_QTAPPEND,	"APPEND" },
497		{ L9P_QTEXCL,	L9P_QTEXCL,	"EXCL" },
498		{ L9P_QTMOUNT,	L9P_QTMOUNT,	"MOUNT" },
499		{ L9P_QTAUTH,	L9P_QTAUTH,	"AUTH" },
500		{ L9P_QTTMP,	L9P_QTTMP,	"TMP" },
501		{ L9P_QTSYMLINK, L9P_QTSYMLINK,	"SYMLINK" },
502		{ 0, 0, NULL }
503	};
504
505	assert(qid != NULL);
506
507	sbuf_cat(sb, str);
508	(void) l9p_describe_bits("<", qid->type, "[]", bits, sb);
509	sbuf_printf(sb, ",%" PRIu32 ",0x%016" PRIx64 ">",
510	    qid->version, qid->path);
511}
512
513/*
514 * Show size.
515 */
516static void
517l9p_describe_size(const char *str, uint64_t size, struct sbuf *sb)
518{
519
520	sbuf_printf(sb, "%s%" PRIu64, str, size);
521}
522
523/*
524 * Show l9stat (including 9P2000.u extensions if appropriate).
525 */
526static void
527l9p_describe_l9stat(const char *str, struct l9p_stat *st,
528    enum l9p_version version, struct sbuf *sb)
529{
530	bool dotu = version >= L9P_2000U;
531
532	assert(st != NULL);
533
534	sbuf_printf(sb, "%stype=0x%04" PRIx32 " dev=0x%08" PRIx32, str,
535	    st->type, st->dev);
536	l9p_describe_qid(" qid=", &st->qid, sb);
537	l9p_describe_ext_perm(" mode=", st->mode, sb);
538	if (st->atime != (uint32_t)-1)
539		sbuf_printf(sb, " atime=%" PRIu32, st->atime);
540	if (st->mtime != (uint32_t)-1)
541		sbuf_printf(sb, " mtime=%" PRIu32, st->mtime);
542	if (st->length != (uint64_t)-1)
543		sbuf_printf(sb, " length=%" PRIu64, st->length);
544	l9p_describe_name(" name=", st->name, sb);
545	/*
546	 * It's pretty common to have NULL name+gid+muid.  They're
547	 * just noise if NULL *and* dot-u; decode only if non-null
548	 * or not-dot-u.
549	 */
550	if (st->uid != NULL || !dotu)
551		l9p_describe_name(" uid=", st->uid, sb);
552	if (st->gid != NULL || !dotu)
553		l9p_describe_name(" gid=", st->gid, sb);
554	if (st->muid != NULL || !dotu)
555		l9p_describe_name(" muid=", st->muid, sb);
556	if (dotu) {
557		if (st->extension != NULL)
558			l9p_describe_name(" extension=", st->extension, sb);
559		sbuf_printf(sb,
560		    " n_uid=%" PRIu32 " n_gid=%" PRIu32 " n_muid=%" PRIu32,
561		    st->n_uid, st->n_gid, st->n_muid);
562	}
563}
564
565static void
566l9p_describe_statfs(const char *str, struct l9p_statfs *st, struct sbuf *sb)
567{
568
569	assert(st != NULL);
570
571	sbuf_printf(sb, "%stype=0x%04lx bsize=%lu blocks=%" PRIu64
572	    " bfree=%" PRIu64 " bavail=%" PRIu64 " files=%" PRIu64
573	    " ffree=%" PRIu64 " fsid=0x%" PRIx64 " namelen=%" PRIu32 ">",
574	    str, (u_long)st->type, (u_long)st->bsize, st->blocks,
575	    st->bfree, st->bavail, st->files,
576	    st->ffree, st->fsid, st->namelen);
577}
578
579/*
580 * Decode a <seconds,nsec> timestamp.
581 *
582 * Perhaps should use asctime_r.  For now, raw values.
583 */
584static void
585l9p_describe_time(struct sbuf *sb, const char *s, uint64_t sec, uint64_t nsec)
586{
587
588	sbuf_cat(sb, s);
589	if (nsec > 999999999)
590		sbuf_printf(sb, "%" PRIu64 ".<invalid nsec %" PRIu64 ">)",
591		    sec, nsec);
592	else
593		sbuf_printf(sb, "%" PRIu64 ".%09" PRIu64, sec, nsec);
594}
595
596/*
597 * Decode readdir data (.L format, variable length names).
598 */
599static void
600l9p_describe_readdir(struct sbuf *sb, struct l9p_f_io *io)
601{
602	uint32_t count;
603#ifdef notyet
604	int i;
605	struct l9p_message msg;
606	struct l9p_dirent de;
607#endif
608
609	if ((count = io->count) == 0) {
610		sbuf_printf(sb, " EOF (count=0)");
611		return;
612	}
613
614	/*
615	 * Can't do this yet because we do not have the original
616	 * req.
617	 */
618#ifdef notyet
619	sbuf_printf(sb, " count=%" PRIu32 " [", count);
620
621	l9p_init_msg(&msg, req, L9P_UNPACK);
622	for (i = 0; msg.lm_size < count; i++) {
623		if (l9p_pudirent(&msg, &de) < 0) {
624			sbuf_printf(sb, " bad count");
625			break;
626		}
627
628		sbuf_printf(sb, i ? ", " : " ");
629		l9p_describe_qid(" qid=", &de.qid, sb);
630		sbuf_printf(sb, " offset=%" PRIu64 " type=%d",
631		    de.offset, de.type);
632		l9p_describe_name(" name=", de.name);
633		free(de.name);
634	}
635	sbuf_printf(sb, "]=%d dir entries", i);
636#else /* notyet */
637	sbuf_printf(sb, " count=%" PRIu32, count);
638#endif
639}
640
641/*
642 * Decode Tgetattr request_mask field.
643 */
644static void
645l9p_describe_getattr_mask(uint64_t request_mask, struct sbuf *sb)
646{
647	static const struct descbits bits[] = {
648		/*
649		 * Note: ALL and BASIC must occur first and second.
650		 * This is a little dirty: it depends on the way the
651		 * describe_bits code clears the values.  If we
652		 * match ALL, we clear all those bits and do not
653		 * match BASIC; if we match BASIC, we clear all
654		 * those bits and do not match individual bits.  Thus
655		 * if we have BASIC but not all the additional bits,
656		 * we'll see, e.g., [BASIC,BTIME,GEN]; if we have
657		 * all the additional bits too, we'll see [ALL].
658		 *
659		 * Since <undec> is true below, we'll also spot any
660		 * bits added to the protocol since we made this table.
661		 */
662		{ L9PL_GETATTR_ALL,	L9PL_GETATTR_ALL,	"ALL" },
663		{ L9PL_GETATTR_BASIC,	L9PL_GETATTR_BASIC,	"BASIC" },
664
665		/* individual bits in BASIC */
666		{ L9PL_GETATTR_MODE,	L9PL_GETATTR_MODE,	"MODE" },
667		{ L9PL_GETATTR_NLINK,	L9PL_GETATTR_NLINK,	"NLINK" },
668		{ L9PL_GETATTR_UID,	L9PL_GETATTR_UID,	"UID" },
669		{ L9PL_GETATTR_GID,	L9PL_GETATTR_GID,	"GID" },
670		{ L9PL_GETATTR_RDEV,	L9PL_GETATTR_RDEV,	"RDEV" },
671		{ L9PL_GETATTR_ATIME,	L9PL_GETATTR_ATIME,	"ATIME" },
672		{ L9PL_GETATTR_MTIME,	L9PL_GETATTR_MTIME,	"MTIME" },
673		{ L9PL_GETATTR_CTIME,	L9PL_GETATTR_CTIME,	"CTIME" },
674		{ L9PL_GETATTR_INO,	L9PL_GETATTR_INO,	"INO" },
675		{ L9PL_GETATTR_SIZE,	L9PL_GETATTR_SIZE,	"SIZE" },
676		{ L9PL_GETATTR_BLOCKS,	L9PL_GETATTR_BLOCKS,	"BLOCKS" },
677
678		/* additional bits in ALL */
679		{ L9PL_GETATTR_BTIME,	L9PL_GETATTR_BTIME,	"BTIME" },
680		{ L9PL_GETATTR_GEN,	L9PL_GETATTR_GEN,	"GEN" },
681		{ L9PL_GETATTR_DATA_VERSION, L9PL_GETATTR_DATA_VERSION,
682							"DATA_VERSION" },
683		{ 0, 0, NULL }
684	};
685
686	(void) l9p_describe_bits(" request_mask=", request_mask, "[]", bits,
687	    sb);
688}
689
690/*
691 * Decode Tunlinkat flags.
692 */
693static void
694l9p_describe_unlinkat_flags(const char *str, uint32_t flags, struct sbuf *sb)
695{
696	static const struct descbits bits[] = {
697		{ L9PL_AT_REMOVEDIR, L9PL_AT_REMOVEDIR, "AT_REMOVEDIR" },
698		{ 0, 0, NULL }
699	};
700
701	(void) l9p_describe_bits(str, flags, "[]", bits, sb);
702}
703
704static const char *
705lookup_linux_errno(uint32_t linux_errno)
706{
707	static char unknown[50];
708
709	/*
710	 * Error numbers in the "base" range (1..ERANGE) are common
711	 * across BSD, MacOS, Linux, and Plan 9.
712	 *
713	 * Error numbers outside that range require translation.
714	 */
715	const char *const table[] = {
716#define X0(name) [name] = name ## _STR
717#define	X(name) [name] = name ## _STR
718		X(LINUX_EAGAIN),
719		X(LINUX_EDEADLK),
720		X(LINUX_ENAMETOOLONG),
721		X(LINUX_ENOLCK),
722		X(LINUX_ENOSYS),
723		X(LINUX_ENOTEMPTY),
724		X(LINUX_ELOOP),
725		X(LINUX_ENOMSG),
726		X(LINUX_EIDRM),
727		X(LINUX_ECHRNG),
728		X(LINUX_EL2NSYNC),
729		X(LINUX_EL3HLT),
730		X(LINUX_EL3RST),
731		X(LINUX_ELNRNG),
732		X(LINUX_EUNATCH),
733		X(LINUX_ENOCSI),
734		X(LINUX_EL2HLT),
735		X(LINUX_EBADE),
736		X(LINUX_EBADR),
737		X(LINUX_EXFULL),
738		X(LINUX_ENOANO),
739		X(LINUX_EBADRQC),
740		X(LINUX_EBADSLT),
741		X(LINUX_EBFONT),
742		X(LINUX_ENOSTR),
743		X(LINUX_ENODATA),
744		X(LINUX_ETIME),
745		X(LINUX_ENOSR),
746		X(LINUX_ENONET),
747		X(LINUX_ENOPKG),
748		X(LINUX_EREMOTE),
749		X(LINUX_ENOLINK),
750		X(LINUX_EADV),
751		X(LINUX_ESRMNT),
752		X(LINUX_ECOMM),
753		X(LINUX_EPROTO),
754		X(LINUX_EMULTIHOP),
755		X(LINUX_EDOTDOT),
756		X(LINUX_EBADMSG),
757		X(LINUX_EOVERFLOW),
758		X(LINUX_ENOTUNIQ),
759		X(LINUX_EBADFD),
760		X(LINUX_EREMCHG),
761		X(LINUX_ELIBACC),
762		X(LINUX_ELIBBAD),
763		X(LINUX_ELIBSCN),
764		X(LINUX_ELIBMAX),
765		X(LINUX_ELIBEXEC),
766		X(LINUX_EILSEQ),
767		X(LINUX_ERESTART),
768		X(LINUX_ESTRPIPE),
769		X(LINUX_EUSERS),
770		X(LINUX_ENOTSOCK),
771		X(LINUX_EDESTADDRREQ),
772		X(LINUX_EMSGSIZE),
773		X(LINUX_EPROTOTYPE),
774		X(LINUX_ENOPROTOOPT),
775		X(LINUX_EPROTONOSUPPORT),
776		X(LINUX_ESOCKTNOSUPPORT),
777		X(LINUX_EOPNOTSUPP),
778		X(LINUX_EPFNOSUPPORT),
779		X(LINUX_EAFNOSUPPORT),
780		X(LINUX_EADDRINUSE),
781		X(LINUX_EADDRNOTAVAIL),
782		X(LINUX_ENETDOWN),
783		X(LINUX_ENETUNREACH),
784		X(LINUX_ENETRESET),
785		X(LINUX_ECONNABORTED),
786		X(LINUX_ECONNRESET),
787		X(LINUX_ENOBUFS),
788		X(LINUX_EISCONN),
789		X(LINUX_ENOTCONN),
790		X(LINUX_ESHUTDOWN),
791		X(LINUX_ETOOMANYREFS),
792		X(LINUX_ETIMEDOUT),
793		X(LINUX_ECONNREFUSED),
794		X(LINUX_EHOSTDOWN),
795		X(LINUX_EHOSTUNREACH),
796		X(LINUX_EALREADY),
797		X(LINUX_EINPROGRESS),
798		X(LINUX_ESTALE),
799		X(LINUX_EUCLEAN),
800		X(LINUX_ENOTNAM),
801		X(LINUX_ENAVAIL),
802		X(LINUX_EISNAM),
803		X(LINUX_EREMOTEIO),
804		X(LINUX_EDQUOT),
805		X(LINUX_ENOMEDIUM),
806		X(LINUX_EMEDIUMTYPE),
807		X(LINUX_ECANCELED),
808		X(LINUX_ENOKEY),
809		X(LINUX_EKEYEXPIRED),
810		X(LINUX_EKEYREVOKED),
811		X(LINUX_EKEYREJECTED),
812		X(LINUX_EOWNERDEAD),
813		X(LINUX_ENOTRECOVERABLE),
814		X(LINUX_ERFKILL),
815		X(LINUX_EHWPOISON),
816#undef X0
817#undef X
818	};
819	if ((size_t)linux_errno < N(table) && table[linux_errno] != NULL)
820		return (table[linux_errno]);
821	if (linux_errno <= ERANGE)
822		return (strerror((int)linux_errno));
823	(void) snprintf(unknown, sizeof(unknown),
824	    "Unknown error %d", linux_errno);
825	return (unknown);
826}
827
828void
829l9p_describe_fcall(union l9p_fcall *fcall, enum l9p_version version,
830    struct sbuf *sb)
831{
832	uint64_t mask;
833	uint8_t type;
834	int i;
835
836	assert(fcall != NULL);
837	assert(sb != NULL);
838	assert(version <= L9P_2000L && version >= L9P_INVALID_VERSION);
839
840	type = fcall->hdr.type;
841
842	if (type < L9P__FIRST || type >= L9P__LAST_PLUS_1 ||
843	    ftype_names[type - L9P__FIRST] == NULL) {
844		const char *rr;
845
846		/*
847		 * Can't say for sure that this distinction --
848		 * an even number is a request, an odd one is
849		 * a response -- will be maintained forever,
850		 * but it's good enough for now.
851		 */
852		rr = (type & 1) != 0 ? "response" : "request";
853		sbuf_printf(sb, "<unknown %s %d> tag=%d", rr, type,
854		    fcall->hdr.tag);
855	} else {
856		sbuf_printf(sb, "%s tag=%d", ftype_names[type - L9P__FIRST],
857		    fcall->hdr.tag);
858	}
859
860	switch (type) {
861	case L9P_TVERSION:
862	case L9P_RVERSION:
863		sbuf_printf(sb, " version=\"%s\" msize=%d", fcall->version.version,
864		    fcall->version.msize);
865		return;
866
867	case L9P_TAUTH:
868		l9p_describe_fid(" afid=", fcall->hdr.fid, sb);
869		sbuf_printf(sb, " uname=\"%s\" aname=\"%s\"",
870		    fcall->tauth.uname, fcall->tauth.aname);
871		return;
872
873	case L9P_TATTACH:
874		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
875		l9p_describe_fid(" afid=", fcall->tattach.afid, sb);
876		sbuf_printf(sb, " uname=\"%s\" aname=\"%s\"",
877		    fcall->tattach.uname, fcall->tattach.aname);
878		if (version >= L9P_2000U)
879			sbuf_printf(sb, " n_uname=%d", fcall->tattach.n_uname);
880		return;
881
882	case L9P_RATTACH:
883		l9p_describe_qid(" ", &fcall->rattach.qid, sb);
884		return;
885
886	case L9P_RERROR:
887		sbuf_printf(sb, " ename=\"%s\" errnum=%d", fcall->error.ename,
888		    fcall->error.errnum);
889		return;
890
891	case L9P_RLERROR:
892		sbuf_printf(sb, " errnum=%d (%s)", fcall->error.errnum,
893		    lookup_linux_errno(fcall->error.errnum));
894		return;
895
896	case L9P_TFLUSH:
897		sbuf_printf(sb, " oldtag=%d", fcall->tflush.oldtag);
898		return;
899
900	case L9P_RFLUSH:
901		return;
902
903	case L9P_TWALK:
904		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
905		l9p_describe_fid(" newfid=", fcall->twalk.newfid, sb);
906		if (fcall->twalk.nwname) {
907			sbuf_cat(sb, " wname=\"");
908			for (i = 0; i < fcall->twalk.nwname; i++)
909				sbuf_printf(sb, "%s%s", i == 0 ? "" : "/",
910				    fcall->twalk.wname[i]);
911			sbuf_cat(sb, "\"");
912		}
913		return;
914
915	case L9P_RWALK:
916		sbuf_printf(sb, " wqid=[");
917		for (i = 0; i < fcall->rwalk.nwqid; i++)
918			l9p_describe_qid(i == 0 ? "" : ",",
919			    &fcall->rwalk.wqid[i], sb);
920		sbuf_cat(sb, "]");
921		return;
922
923	case L9P_TOPEN:
924		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
925		l9p_describe_mode(" mode=", fcall->tcreate.mode, sb);
926		return;
927
928	case L9P_ROPEN:
929		l9p_describe_qid(" qid=", &fcall->ropen.qid, sb);
930		sbuf_printf(sb, " iounit=%d", fcall->ropen.iounit);
931		return;
932
933	case L9P_TCREATE:
934		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
935		l9p_describe_name(" name=", fcall->tcreate.name, sb);
936		l9p_describe_ext_perm(" perm=", fcall->tcreate.perm, sb);
937		l9p_describe_mode(" mode=", fcall->tcreate.mode, sb);
938		if (version >= L9P_2000U && fcall->tcreate.extension != NULL)
939			l9p_describe_name(" extension=",
940			    fcall->tcreate.extension, sb);
941		return;
942
943	case L9P_RCREATE:
944		l9p_describe_qid(" qid=", &fcall->rcreate.qid, sb);
945		sbuf_printf(sb, " iounit=%d", fcall->rcreate.iounit);
946		return;
947
948	case L9P_TREAD:
949		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
950		sbuf_printf(sb, " offset=%" PRIu64 " count=%" PRIu32,
951		    fcall->io.offset, fcall->io.count);
952		return;
953
954	case L9P_RREAD:
955	case L9P_RWRITE:
956		sbuf_printf(sb, " count=%" PRIu32, fcall->io.count);
957		return;
958
959	case L9P_TWRITE:
960	case L9P_TREADDIR:
961		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
962		sbuf_printf(sb, " offset=%" PRIu64 " count=%" PRIu32,
963		    fcall->io.offset, fcall->io.count);
964		return;
965
966	case L9P_TCLUNK:
967		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
968		return;
969
970	case L9P_RCLUNK:
971		return;
972
973	case L9P_TREMOVE:
974		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
975		return;
976
977	case L9P_RREMOVE:
978		return;
979
980	case L9P_TSTAT:
981		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
982		return;
983
984	case L9P_RSTAT:
985		l9p_describe_l9stat(" ", &fcall->rstat.stat, version, sb);
986		return;
987
988	case L9P_TWSTAT:
989		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
990		l9p_describe_l9stat(" ", &fcall->twstat.stat, version, sb);
991		return;
992
993	case L9P_RWSTAT:
994		return;
995
996	case L9P_TSTATFS:
997		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
998		return;
999
1000	case L9P_RSTATFS:
1001		l9p_describe_statfs(" ", &fcall->rstatfs.statfs, sb);
1002		return;
1003
1004	case L9P_TLOPEN:
1005		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1006		l9p_describe_lflags(" flags=", fcall->tlcreate.flags, sb);
1007		return;
1008
1009	case L9P_RLOPEN:
1010		l9p_describe_qid(" qid=", &fcall->rlopen.qid, sb);
1011		sbuf_printf(sb, " iounit=%d", fcall->rlopen.iounit);
1012		return;
1013
1014	case L9P_TLCREATE:
1015		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1016		l9p_describe_name(" name=", fcall->tlcreate.name, sb);
1017		/* confusing: "flags" is open-mode, "mode" is permissions */
1018		l9p_describe_lflags(" flags=", fcall->tlcreate.flags, sb);
1019		/* TLCREATE mode/permissions have S_IFREG (0x8000) set */
1020		l9p_describe_lperm(" mode=", fcall->tlcreate.mode, sb);
1021		l9p_describe_ugid(" gid=", fcall->tlcreate.gid, sb);
1022		return;
1023
1024	case L9P_RLCREATE:
1025		l9p_describe_qid(" qid=", &fcall->rlcreate.qid, sb);
1026		sbuf_printf(sb, " iounit=%d", fcall->rlcreate.iounit);
1027		return;
1028
1029	case L9P_TSYMLINK:
1030		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1031		l9p_describe_name(" name=", fcall->tsymlink.name, sb);
1032		l9p_describe_name(" symtgt=", fcall->tsymlink.symtgt, sb);
1033		l9p_describe_ugid(" gid=", fcall->tsymlink.gid, sb);
1034		return;
1035
1036	case L9P_RSYMLINK:
1037		l9p_describe_qid(" qid=", &fcall->ropen.qid, sb);
1038		return;
1039
1040	case L9P_TMKNOD:
1041		l9p_describe_fid(" dfid=", fcall->hdr.fid, sb);
1042		l9p_describe_name(" name=", fcall->tmknod.name, sb);
1043		/*
1044		 * TMKNOD mode/permissions have S_IFBLK/S_IFCHR/S_IFIFO
1045		 * bits.  The major and minor values are only meaningful
1046		 * for S_IFBLK and S_IFCHR, but just decode always here.
1047		 */
1048		l9p_describe_lperm(" mode=", fcall->tmknod.mode, sb);
1049		sbuf_printf(sb, " major=%u minor=%u",
1050		    fcall->tmknod.major, fcall->tmknod.minor);
1051		l9p_describe_ugid(" gid=", fcall->tmknod.gid, sb);
1052		return;
1053
1054	case L9P_RMKNOD:
1055		l9p_describe_qid(" qid=", &fcall->rmknod.qid, sb);
1056		return;
1057
1058	case L9P_TRENAME:
1059		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1060		l9p_describe_fid(" dfid=", fcall->trename.dfid, sb);
1061		l9p_describe_name(" name=", fcall->trename.name, sb);
1062		return;
1063
1064	case L9P_RRENAME:
1065		return;
1066
1067	case L9P_TREADLINK:
1068		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1069		return;
1070
1071	case L9P_RREADLINK:
1072		l9p_describe_name(" target=", fcall->rreadlink.target, sb);
1073		return;
1074
1075	case L9P_TGETATTR:
1076		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1077		l9p_describe_getattr_mask(fcall->tgetattr.request_mask, sb);
1078		return;
1079
1080	case L9P_RGETATTR:
1081		/* Don't need to decode bits: they're implied by the output */
1082		mask = fcall->rgetattr.valid;
1083		sbuf_printf(sb, " valid=0x%016" PRIx64, mask);
1084		l9p_describe_qid(" qid=", &fcall->rgetattr.qid, sb);
1085		if (mask & L9PL_GETATTR_MODE)
1086			l9p_describe_lperm(" mode=", fcall->rgetattr.mode, sb);
1087		if (mask & L9PL_GETATTR_UID)
1088			l9p_describe_ugid(" uid=", fcall->rgetattr.uid, sb);
1089		if (mask & L9PL_GETATTR_GID)
1090			l9p_describe_ugid(" gid=", fcall->rgetattr.gid, sb);
1091		if (mask & L9PL_GETATTR_NLINK)
1092			sbuf_printf(sb, " nlink=%" PRIu64,
1093			    fcall->rgetattr.nlink);
1094		if (mask & L9PL_GETATTR_RDEV)
1095			sbuf_printf(sb, " rdev=0x%" PRIx64,
1096			    fcall->rgetattr.rdev);
1097		if (mask & L9PL_GETATTR_SIZE)
1098			l9p_describe_size(" size=", fcall->rgetattr.size, sb);
1099		if (mask & L9PL_GETATTR_BLOCKS)
1100			sbuf_printf(sb, " blksize=%" PRIu64 " blocks=%" PRIu64,
1101			    fcall->rgetattr.blksize, fcall->rgetattr.blocks);
1102		if (mask & L9PL_GETATTR_ATIME)
1103			l9p_describe_time(sb, " atime=",
1104			    fcall->rgetattr.atime_sec,
1105			    fcall->rgetattr.atime_nsec);
1106		if (mask & L9PL_GETATTR_MTIME)
1107			l9p_describe_time(sb, " mtime=",
1108			    fcall->rgetattr.mtime_sec,
1109			    fcall->rgetattr.mtime_nsec);
1110		if (mask & L9PL_GETATTR_CTIME)
1111			l9p_describe_time(sb, " ctime=",
1112			    fcall->rgetattr.ctime_sec,
1113			    fcall->rgetattr.ctime_nsec);
1114		if (mask & L9PL_GETATTR_BTIME)
1115			l9p_describe_time(sb, " btime=",
1116			    fcall->rgetattr.btime_sec,
1117			    fcall->rgetattr.btime_nsec);
1118		if (mask & L9PL_GETATTR_GEN)
1119			sbuf_printf(sb, " gen=0x%" PRIx64, fcall->rgetattr.gen);
1120		if (mask & L9PL_GETATTR_DATA_VERSION)
1121			sbuf_printf(sb, " data_version=0x%" PRIx64,
1122			    fcall->rgetattr.data_version);
1123		return;
1124
1125	case L9P_TSETATTR:
1126		/* As with RGETATTR, we'll imply decode via output. */
1127		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1128		mask = fcall->tsetattr.valid;
1129		/* NB: tsetattr valid mask is only 32 bits, hence %08x */
1130		sbuf_printf(sb, " valid=0x%08" PRIx64, mask);
1131		if (mask & L9PL_SETATTR_MODE)
1132			l9p_describe_lperm(" mode=", fcall->tsetattr.mode, sb);
1133		if (mask & L9PL_SETATTR_UID)
1134			l9p_describe_ugid(" uid=", fcall->tsetattr.uid, sb);
1135		if (mask & L9PL_SETATTR_GID)
1136			l9p_describe_ugid(" uid=", fcall->tsetattr.gid, sb);
1137		if (mask & L9PL_SETATTR_SIZE)
1138			l9p_describe_size(" size=", fcall->tsetattr.size, sb);
1139		if (mask & L9PL_SETATTR_ATIME) {
1140			if (mask & L9PL_SETATTR_ATIME_SET)
1141				l9p_describe_time(sb, " atime=",
1142				    fcall->tsetattr.atime_sec,
1143				    fcall->tsetattr.atime_nsec);
1144			else
1145				sbuf_cat(sb, " atime=now");
1146		}
1147		if (mask & L9PL_SETATTR_MTIME) {
1148			if (mask & L9PL_SETATTR_MTIME_SET)
1149				l9p_describe_time(sb, " mtime=",
1150				    fcall->tsetattr.mtime_sec,
1151				    fcall->tsetattr.mtime_nsec);
1152			else
1153				sbuf_cat(sb, " mtime=now");
1154		}
1155		if (mask & L9PL_SETATTR_CTIME)
1156			sbuf_cat(sb, " ctime=now");
1157		return;
1158
1159	case L9P_RSETATTR:
1160		return;
1161
1162	case L9P_TXATTRWALK:
1163		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1164		l9p_describe_fid(" newfid=", fcall->txattrwalk.newfid, sb);
1165		l9p_describe_name(" name=", fcall->txattrwalk.name, sb);
1166		return;
1167
1168	case L9P_RXATTRWALK:
1169		l9p_describe_size(" size=", fcall->rxattrwalk.size, sb);
1170		return;
1171
1172	case L9P_TXATTRCREATE:
1173		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1174		l9p_describe_name(" name=", fcall->txattrcreate.name, sb);
1175		l9p_describe_size(" size=", fcall->txattrcreate.attr_size, sb);
1176		sbuf_printf(sb, " flags=%" PRIu32, fcall->txattrcreate.flags);
1177		return;
1178
1179	case L9P_RXATTRCREATE:
1180		return;
1181
1182	case L9P_RREADDIR:
1183		l9p_describe_readdir(sb, &fcall->io);
1184		return;
1185
1186	case L9P_TFSYNC:
1187		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1188		return;
1189
1190	case L9P_RFSYNC:
1191		return;
1192
1193	case L9P_TLOCK:
1194		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1195		/* decode better later */
1196		sbuf_printf(sb, " type=%d flags=0x%" PRIx32
1197		    " start=%" PRIu64 " length=%" PRIu64
1198		    " proc_id=0x%" PRIx32 " client_id=\"%s\"",
1199		    fcall->tlock.type, fcall->tlock.flags,
1200		    fcall->tlock.start, fcall->tlock.length,
1201		    fcall->tlock.proc_id, fcall->tlock.client_id);
1202		return;
1203
1204	case L9P_RLOCK:
1205		sbuf_printf(sb, " status=%d", fcall->rlock.status);
1206		return;
1207
1208	case L9P_TGETLOCK:
1209		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1210		/* FALLTHROUGH */
1211
1212	case L9P_RGETLOCK:
1213		/* decode better later */
1214		sbuf_printf(sb, " type=%d "
1215		    " start=%" PRIu64 " length=%" PRIu64
1216		    " proc_id=0x%" PRIx32 " client_id=\"%s\"",
1217		    fcall->getlock.type,
1218		    fcall->getlock.start, fcall->getlock.length,
1219		    fcall->getlock.proc_id, fcall->getlock.client_id);
1220		return;
1221
1222	case L9P_TLINK:
1223		l9p_describe_fid(" dfid=", fcall->tlink.dfid, sb);
1224		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1225		l9p_describe_name(" name=", fcall->tlink.name, sb);
1226		return;
1227
1228	case L9P_RLINK:
1229		return;
1230
1231	case L9P_TMKDIR:
1232		l9p_describe_fid(" fid=", fcall->hdr.fid, sb);
1233		l9p_describe_name(" name=", fcall->tmkdir.name, sb);
1234		/* TMKDIR mode/permissions have S_IFDIR set */
1235		l9p_describe_lperm(" mode=", fcall->tmkdir.mode, sb);
1236		l9p_describe_ugid(" gid=", fcall->tmkdir.gid, sb);
1237		return;
1238
1239	case L9P_RMKDIR:
1240		l9p_describe_qid(" qid=", &fcall->rmkdir.qid, sb);
1241		return;
1242
1243	case L9P_TRENAMEAT:
1244		l9p_describe_fid(" olddirfid=", fcall->hdr.fid, sb);
1245		l9p_describe_name(" oldname=", fcall->trenameat.oldname,
1246		    sb);
1247		l9p_describe_fid(" newdirfid=", fcall->trenameat.newdirfid, sb);
1248		l9p_describe_name(" newname=", fcall->trenameat.newname,
1249		    sb);
1250		return;
1251
1252	case L9P_RRENAMEAT:
1253		return;
1254
1255	case L9P_TUNLINKAT:
1256		l9p_describe_fid(" dirfd=", fcall->hdr.fid, sb);
1257		l9p_describe_name(" name=", fcall->tunlinkat.name, sb);
1258		l9p_describe_unlinkat_flags(" flags=",
1259		    fcall->tunlinkat.flags, sb);
1260		return;
1261
1262	case L9P_RUNLINKAT:
1263		return;
1264
1265	default:
1266		sbuf_printf(sb, " <missing case in %s()>", __func__);
1267	}
1268}
1269