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