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