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