Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/lib9p/utils.c
39475 views
1
/*
2
* Copyright 2016 Jakub Klama <[email protected]>
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
}
1269
1270