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