]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/lib9p/utils.c
ping(8): Fix a mandoc related issue
[FreeBSD/FreeBSD.git] / contrib / lib9p / utils.c
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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 }