xref: /minix/minix/usr.bin/trace/service/vfs.c (revision 0a6a1f1d)
1 
2 #include "inc.h"
3 
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <dirent.h>
7 #include <sys/mount.h>
8 #include <sys/resource.h>
9 
10 /*
11  * This function should always be used when printing a file descriptor.  It
12  * currently offers no benefit, but will in the future allow for features such
13  * as color highlighting and tracking of specific open files (TODO).
14  */
15 void
16 put_fd(struct trace_proc * proc, const char * name, int fd)
17 {
18 
19 	put_value(proc, name, "%d", fd);
20 }
21 
22 static int
23 vfs_read_out(struct trace_proc * proc, const message *m_out)
24 {
25 
26 	put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
27 
28 	return CT_NOTDONE;
29 }
30 
31 static void
32 vfs_read_in(struct trace_proc * proc, const message *m_out,
33 	const message *m_in, int failed)
34 {
35 
36 	put_buf(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf,
37 	    m_in->m_type);
38 	put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
39 	put_equals(proc);
40 	put_result(proc);
41 }
42 
43 static int
44 vfs_write_out(struct trace_proc * proc, const message *m_out)
45 {
46 
47 	put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
48 	put_buf(proc, "buf", 0, m_out->m_lc_vfs_readwrite.buf,
49 	    m_out->m_lc_vfs_readwrite.len);
50 	put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
51 
52 	return CT_DONE;
53 }
54 
55 static void
56 put_lseek_whence(struct trace_proc * proc, const char * name, int whence)
57 {
58 	const char *text = NULL;
59 
60 	if (!valuesonly) {
61 		switch (whence) {
62 		TEXT(SEEK_SET);
63 		TEXT(SEEK_CUR);
64 		TEXT(SEEK_END);
65 		}
66 	}
67 
68 	if (text != NULL)
69 		put_field(proc, name, text);
70 	else
71 		put_value(proc, name, "%d", whence);
72 }
73 
74 static int
75 vfs_lseek_out(struct trace_proc * proc, const message * m_out)
76 {
77 
78 	put_fd(proc, "fd", m_out->m_lc_vfs_lseek.fd);
79 	put_value(proc, "offset", "%"PRId64, m_out->m_lc_vfs_lseek.offset);
80 	put_lseek_whence(proc, "whence", m_out->m_lc_vfs_lseek.whence);
81 
82 	return CT_DONE;
83 }
84 
85 static void
86 vfs_lseek_in(struct trace_proc * proc, const message * __unused m_out,
87 	const message * m_in, int failed)
88 {
89 
90 	if (!failed)
91 		put_value(proc, NULL, "%"PRId64, m_in->m_vfs_lc_lseek.offset);
92 	else
93 		put_result(proc);
94 }
95 
96 static const struct flags open_flags[] = {
97 	FLAG_MASK(O_ACCMODE, O_RDONLY),
98 	FLAG_MASK(O_ACCMODE, O_WRONLY),
99 	FLAG_MASK(O_ACCMODE, O_RDWR),
100 #define ACCMODE_ENTRIES 3	/* the first N entries are for O_ACCMODE */
101 	FLAG(O_NONBLOCK),
102 	FLAG(O_APPEND),
103 	FLAG(O_SHLOCK),
104 	FLAG(O_EXLOCK),
105 	FLAG(O_ASYNC),
106 	FLAG(O_SYNC),
107 	FLAG(O_NOFOLLOW),
108 	FLAG(O_CREAT),
109 	FLAG(O_TRUNC),
110 	FLAG(O_EXCL),
111 	FLAG(O_NOCTTY),
112 	FLAG(O_DSYNC),
113 	FLAG(O_RSYNC),
114 	FLAG(O_ALT_IO),
115 	FLAG(O_DIRECT),
116 	FLAG(O_DIRECTORY),
117 	FLAG(O_CLOEXEC),
118 	FLAG(O_SEARCH),
119 	FLAG(O_NOSIGPIPE),
120 };
121 
122 static void
123 put_open_flags(struct trace_proc * proc, const char * name, int value,
124 	int full)
125 {
126 	const struct flags *fp;
127 	unsigned int num;
128 
129 	fp = open_flags;
130 	num = COUNT(open_flags);
131 
132 	/*
133 	 * If we're not printing a full open()-style set of flags, but instead
134 	 * just a loose set of flags, then skip the access mode altogether,
135 	 * otherwise we'd be printing O_RDONLY when no access mode is given.
136 	 */
137 	if (!full) {
138 		fp += ACCMODE_ENTRIES;
139 		num -= ACCMODE_ENTRIES;
140 	}
141 
142 	put_flags(proc, name, fp, num, "0x%x", value);
143 }
144 
145 static const struct flags mode_flags[] = {
146 	FLAG_MASK(S_IFMT, S_IFIFO),
147 	FLAG_MASK(S_IFMT, S_IFCHR),
148 	FLAG_MASK(S_IFMT, S_IFDIR),
149 	FLAG_MASK(S_IFMT, S_IFBLK),
150 	FLAG_MASK(S_IFMT, S_IFREG),
151 	FLAG_MASK(S_IFMT, S_IFLNK),
152 	FLAG_MASK(S_IFMT, S_IFSOCK),
153 	FLAG_MASK(S_IFMT, S_IFWHT),
154 	FLAG(S_ARCH1),
155 	FLAG(S_ARCH2),
156 	FLAG(S_ISUID),
157 	FLAG(S_ISGID),
158 	FLAG(S_ISTXT),
159 };
160 
161 /* Do not use %04o instead of 0%03o; it is octal even if greater than 0777. */
162 #define put_mode(p, n, v) \
163 	put_flags(p, n, mode_flags, COUNT(mode_flags), "0%03o", v)
164 
165 static void
166 put_path(struct trace_proc * proc, const message * m_out)
167 {
168 	size_t len;
169 
170 	if ((len = m_out->m_lc_vfs_path.len) <= M_PATH_STRING_MAX)
171 		put_buf(proc, "path", PF_LOCADDR | PF_PATH,
172 		    (vir_bytes)m_out->m_lc_vfs_path.buf, len);
173 	else
174 		put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_path.name, len);
175 }
176 
177 static int
178 vfs_open_out(struct trace_proc * proc, const message * m_out)
179 {
180 
181 	put_path(proc, m_out);
182 	put_open_flags(proc, "flags", m_out->m_lc_vfs_path.flags,
183 	    TRUE /*full*/);
184 
185 	return CT_DONE;
186 }
187 
188 /* This function is shared between creat and open. */
189 static void
190 vfs_open_in(struct trace_proc * proc, const message * __unused m_out,
191 	const message * m_in, int failed)
192 {
193 
194 	if (!failed)
195 		put_fd(proc, NULL, m_in->m_type);
196 	else
197 		put_result(proc);
198 }
199 
200 static int
201 vfs_creat_out(struct trace_proc * proc, const message * m_out)
202 {
203 
204 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_creat.name,
205 	    m_out->m_lc_vfs_creat.len);
206 	put_open_flags(proc, "flags", m_out->m_lc_vfs_creat.flags,
207 	    TRUE /*full*/);
208 	put_mode(proc, "mode", m_out->m_lc_vfs_creat.mode);
209 
210 	return CT_DONE;
211 }
212 
213 static int
214 vfs_close_out(struct trace_proc * proc, const message * m_out)
215 {
216 
217 	put_fd(proc, "fd", m_out->m_lc_vfs_close.fd);
218 
219 	return CT_DONE;
220 }
221 
222 /* This function is used for link, rename, and symlink. */
223 static int
224 vfs_link_out(struct trace_proc * proc, const message * m_out)
225 {
226 
227 	put_buf(proc, "path1", PF_PATH, m_out->m_lc_vfs_link.name1,
228 	    m_out->m_lc_vfs_link.len1);
229 	put_buf(proc, "path2", PF_PATH, m_out->m_lc_vfs_link.name2,
230 	    m_out->m_lc_vfs_link.len2);
231 
232 	return CT_DONE;
233 }
234 
235 static int
236 vfs_path_out(struct trace_proc * proc, const message * m_out)
237 {
238 
239 	put_path(proc, m_out);
240 
241 	return CT_DONE;
242 }
243 
244 static int
245 vfs_path_mode_out(struct trace_proc * proc, const message * m_out)
246 {
247 
248 	put_path(proc, m_out);
249 	put_mode(proc, "mode", m_out->m_lc_vfs_path.mode);
250 
251 	return CT_DONE;
252 }
253 
254 void
255 put_dev(struct trace_proc * proc, const char * name, dev_t dev)
256 {
257 	devmajor_t major;
258 	devminor_t minor;
259 
260 	major = major(dev);
261 	minor = minor(dev);
262 
263 	/* The value 0 ("no device") should print as "0". */
264 	if (dev != 0 && makedev(major, minor) == dev && !valuesonly)
265 		put_value(proc, name, "<%d,%d>", major, minor);
266 	else
267 		put_value(proc, name, "%"PRIu64, dev);
268 }
269 
270 static int
271 vfs_mknod_out(struct trace_proc * proc, const message * m_out)
272 {
273 
274 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mknod.name,
275 	    m_out->m_lc_vfs_mknod.len);
276 	put_mode(proc, "mode", m_out->m_lc_vfs_mknod.mode);
277 	put_dev(proc, "dev", m_out->m_lc_vfs_mknod.device);
278 
279 	return CT_DONE;
280 }
281 
282 static int
283 vfs_chown_out(struct trace_proc * proc, const message * m_out)
284 {
285 
286 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_chown.name,
287 	    m_out->m_lc_vfs_chown.len);
288 	/* -1 means "keep the current value" so print as signed */
289 	put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner);
290 	put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group);
291 
292 	return CT_DONE;
293 }
294 
295 /* TODO: expand this to the full ST_ set. */
296 static const struct flags mount_flags[] = {
297 	FLAG(MNT_RDONLY),
298 };
299 
300 static int
301 vfs_mount_out(struct trace_proc * proc, const message * m_out)
302 {
303 
304 	put_buf(proc, "special", PF_PATH, m_out->m_lc_vfs_mount.dev,
305 	    m_out->m_lc_vfs_mount.devlen);
306 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mount.path,
307 	    m_out->m_lc_vfs_mount.pathlen);
308 	put_flags(proc, "flags", mount_flags, COUNT(mount_flags), "0x%x",
309 	    m_out->m_lc_vfs_mount.flags);
310 	put_buf(proc, "type", PF_STRING, m_out->m_lc_vfs_mount.type,
311 	    m_out->m_lc_vfs_mount.typelen);
312 	put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_mount.label,
313 	    m_out->m_lc_vfs_mount.labellen);
314 
315 	return CT_DONE;
316 }
317 
318 static int
319 vfs_umount_out(struct trace_proc * proc, const message * m_out)
320 {
321 
322 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_umount.name,
323 	    m_out->m_lc_vfs_umount.namelen);
324 
325 	return CT_DONE;
326 }
327 
328 static void
329 vfs_umount_in(struct trace_proc * proc, const message * m_out,
330 	const message * __unused m_in, int failed)
331 {
332 
333 	put_result(proc);
334 
335 	if (!failed) {
336 		put_open(proc, NULL, 0, "(", ", ");
337 		put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_umount.label,
338 		    m_out->m_lc_vfs_umount.labellen);
339 
340 		put_close(proc, ")");
341 	}
342 }
343 
344 
345 static const struct flags access_flags[] = {
346 	FLAG_ZERO(F_OK),
347 	FLAG(R_OK),
348 	FLAG(W_OK),
349 	FLAG(X_OK),
350 };
351 
352 static int
353 vfs_access_out(struct trace_proc * proc, const message * m_out)
354 {
355 
356 	put_path(proc, m_out);
357 	put_flags(proc, "mode", access_flags, COUNT(access_flags), "0x%x",
358 	    m_out->m_lc_vfs_path.mode);
359 
360 	return CT_DONE;
361 }
362 
363 static int
364 vfs_readlink_out(struct trace_proc * proc, const message * m_out)
365 {
366 
367 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_readlink.name,
368 	    m_out->m_lc_vfs_readlink.namelen);
369 
370 	return CT_NOTDONE;
371 }
372 
373 static void
374 vfs_readlink_in(struct trace_proc * proc, const message * m_out,
375 	const message * m_in, int failed)
376 {
377 
378 	/* The call does not return a string, so do not use PF_STRING here. */
379 	put_buf(proc, "buf", failed, m_out->m_lc_vfs_readlink.buf,
380 	    m_in->m_type);
381 	put_value(proc, "bufsize", "%zd", m_out->m_lc_vfs_readlink.bufsize);
382 	put_equals(proc);
383 	put_result(proc);
384 }
385 
386 static void
387 put_struct_stat(struct trace_proc * proc, const char * name, int flags,
388 	vir_bytes addr)
389 {
390 	struct stat buf;
391 	int is_special;
392 
393 	if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
394 		return;
395 
396 	/*
397 	 * The combination of struct stat's frequent usage and large number of
398 	 * fields makes this structure a pain to print.  For now, the idea is
399 	 * that for verbosity level 0, we print the mode, and the target device
400 	 * for block/char special files or the file size for all other files.
401 	 * For higher verbosity levels, largely maintain the structure's own
402 	 * order of fields.  Violate this general structure printing rule for
403 	 * some fields though, because the actual field order in struct stat is
404 	 * downright ridiculous.  Like elsewhere, for verbosity level 1 print
405 	 * all fields with meaningful values, and for verbosity level 2 just
406 	 * print everything, including fields that are known to be not yet
407 	 * supported and fields that contain known values.
408 	 */
409 	is_special = (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
410 
411 	if (verbose > 0) {
412 		put_dev(proc, "st_dev", buf.st_dev);
413 		put_value(proc, "st_ino", "%"PRId64, buf.st_ino);
414 	}
415 	put_mode(proc, "st_mode", buf.st_mode);
416 	if (verbose > 0) {
417 		put_value(proc, "st_nlink", "%u", buf.st_nlink);
418 		put_value(proc, "st_uid", "%u", buf.st_uid);
419 		put_value(proc, "st_gid", "%u", buf.st_gid);
420 	}
421 	if (is_special || verbose > 1)
422 		put_dev(proc, "st_rdev", buf.st_rdev);
423 	if (verbose > 0) {
424 		/*
425 		 * TODO: print the nanosecond part, but possibly only if we are
426 		 * not actually interpreting the time as a date (another TODO),
427 		 * and/or possibly only with verbose > 1 (largely unsupported).
428 		 */
429 		put_time(proc, "st_atime", buf.st_atime);
430 		put_time(proc, "st_mtime", buf.st_mtime);
431 		put_time(proc, "st_ctime", buf.st_ctime);
432 	}
433 	if (verbose > 1) /* not yet supported on MINIX3 */
434 		put_time(proc, "st_birthtime", buf.st_birthtime);
435 	if (!is_special || verbose > 1)
436 		put_value(proc, "st_size", "%"PRId64, buf.st_size);
437 	if (verbose > 0) {
438 		put_value(proc, "st_blocks", "%"PRId64, buf.st_blocks);
439 		put_value(proc, "st_blksize", "%"PRId32, buf.st_blksize);
440 	}
441 	if (verbose > 1) {
442 		put_value(proc, "st_flags", "%"PRIu32, buf.st_flags);
443 		put_value(proc, "st_gen", "%"PRIu32, buf.st_gen);
444 	}
445 
446 	put_close_struct(proc, verbose > 1);
447 }
448 
449 static int
450 vfs_stat_out(struct trace_proc * proc, const message * m_out)
451 {
452 
453 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_stat.name,
454 	    m_out->m_lc_vfs_stat.len);
455 
456 	return CT_NOTDONE;
457 }
458 
459 static void
460 vfs_stat_in(struct trace_proc * proc, const message * m_out,
461 	const message * __unused m_in, int failed)
462 {
463 
464 	put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_stat.buf);
465 	put_equals(proc);
466 	put_result(proc);
467 }
468 
469 static int
470 vfs_fstat_out(struct trace_proc * proc, const message * m_out)
471 {
472 
473 	put_fd(proc, "fd", m_out->m_lc_vfs_fstat.fd);
474 
475 	return CT_NOTDONE;
476 }
477 
478 static void
479 vfs_fstat_in(struct trace_proc * proc, const message * m_out,
480 	const message * __unused m_in, int failed)
481 {
482 
483 	put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_fstat.buf);
484 	put_equals(proc);
485 	put_result(proc);
486 }
487 
488 static int
489 vfs_ioctl_out(struct trace_proc * proc, const message * m_out)
490 {
491 
492 	put_fd(proc, "fd", m_out->m_lc_vfs_ioctl.fd);
493 	put_ioctl_req(proc, "req", m_out->m_lc_vfs_ioctl.req,
494 	    FALSE /*is_svrctl*/);
495 	return put_ioctl_arg_out(proc, "arg", m_out->m_lc_vfs_ioctl.req,
496 	    (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/);
497 }
498 
499 static void
500 vfs_ioctl_in(struct trace_proc * proc, const message * m_out,
501 	const message * __unused m_in, int failed)
502 {
503 
504 	put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_vfs_ioctl.req,
505 	    (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/);
506 }
507 
508 static void
509 put_fcntl_cmd(struct trace_proc * proc, const char * name, int cmd)
510 {
511 	const char *text = NULL;
512 
513 	if (!valuesonly) {
514 		switch (cmd) {
515 		TEXT(F_DUPFD);
516 		TEXT(F_GETFD);
517 		TEXT(F_SETFD);
518 		TEXT(F_GETFL);
519 		TEXT(F_SETFL);
520 		TEXT(F_GETOWN);
521 		TEXT(F_SETOWN);
522 		TEXT(F_GETLK);
523 		TEXT(F_SETLK);
524 		TEXT(F_SETLKW);
525 		TEXT(F_CLOSEM);
526 		TEXT(F_MAXFD);
527 		TEXT(F_DUPFD_CLOEXEC);
528 		TEXT(F_GETNOSIGPIPE);
529 		TEXT(F_SETNOSIGPIPE);
530 		TEXT(F_FREESP);
531 		TEXT(F_FLUSH_FS_CACHE);
532 		}
533 	}
534 
535 	if (text != NULL)
536 		put_field(proc, name, text);
537 	else
538 		put_value(proc, name, "%d", cmd);
539 }
540 
541 static const struct flags fd_flags[] = {
542 	FLAG(FD_CLOEXEC),
543 };
544 
545 #define put_fd_flags(p, n, v) \
546 	put_flags(p, n, fd_flags, COUNT(fd_flags), "0x%x", v)
547 
548 static void
549 put_flock_type(struct trace_proc * proc, const char * name, int type)
550 {
551 	const char *text = NULL;
552 
553 	if (!valuesonly) {
554 		switch (type) {
555 		TEXT(F_RDLCK);
556 		TEXT(F_UNLCK);
557 		TEXT(F_WRLCK);
558 		}
559 	}
560 
561 	if (text != NULL)
562 		put_field(proc, name, text);
563 	else
564 		put_value(proc, name, "%d", type);
565 }
566 
567 /*
568  * With PF_FULL, also print l_pid, unless l_type is F_UNLCK in which case
569  * only that type is printed.   With PF_ALT, print only l_whence/l_start/l_len.
570  */
571 static void
572 put_struct_flock(struct trace_proc * proc, const char * name, int flags,
573 	vir_bytes addr)
574 {
575 	struct flock flock;
576 	int limited;
577 
578 	if (!put_open_struct(proc, name, flags, addr, &flock, sizeof(flock)))
579 		return;
580 
581 	limited = ((flags & PF_FULL) && flock.l_type == F_UNLCK);
582 
583 	if (!(flags & PF_ALT))
584 		put_flock_type(proc, "l_type", flock.l_type);
585 	if (!limited) {
586 		put_lseek_whence(proc, "l_whence", flock.l_whence);
587 		put_value(proc, "l_start", "%"PRId64, flock.l_start);
588 		put_value(proc, "l_len", "%"PRId64, flock.l_len);
589 		if (flags & PF_FULL)
590 			put_value(proc, "l_pid", "%d", flock.l_pid);
591 	}
592 
593 	put_close_struct(proc, TRUE /*all*/);
594 }
595 
596 static int
597 vfs_fcntl_out(struct trace_proc * proc, const message * m_out)
598 {
599 	int full;
600 
601 	put_fd(proc, "fd", m_out->m_lc_vfs_fcntl.fd);
602 	put_fcntl_cmd(proc, "cmd", m_out->m_lc_vfs_fcntl.cmd);
603 
604 	switch (m_out->m_lc_vfs_fcntl.cmd) {
605 	case F_DUPFD:
606 	case F_DUPFD_CLOEXEC:
607 		put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int);
608 		break;
609 	case F_SETFD:
610 		put_fd_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int);
611 		break;
612 	case F_SETFL:
613 		/*
614 		 * One of those difficult cases: the access mode is ignored, so
615 		 * we don't want to print O_RDONLY if it is not given.  On the
616 		 * other hand, fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_..) is
617 		 * a fairly common construction, in which case we don't want to
618 		 * print eg O_..|0x2 if the access mode is O_RDWR.  Thus, we
619 		 * compromise: show the access mode if any of its bits are set.
620 		 */
621 		put_open_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int,
622 		    m_out->m_lc_vfs_fcntl.arg_int & O_ACCMODE /*full*/);
623 		break;
624 	case F_SETLK:
625 	case F_SETLKW:
626 		put_struct_flock(proc, "lkp", 0,
627 		    m_out->m_lc_vfs_fcntl.arg_ptr);
628 		break;
629 	case F_FREESP:
630 		put_struct_flock(proc, "lkp", PF_ALT,
631 		    m_out->m_lc_vfs_fcntl.arg_ptr);
632 		break;
633 	case F_SETNOSIGPIPE:
634 		put_value(proc, "arg", "%d", m_out->m_lc_vfs_fcntl.arg_int);
635 		break;
636 	}
637 
638 	return (m_out->m_lc_vfs_fcntl.cmd != F_GETLK) ? CT_DONE : CT_NOTDONE;
639 }
640 
641 static void
642 vfs_fcntl_in(struct trace_proc * proc, const message * m_out,
643 	const message * m_in, int failed)
644 {
645 
646 	switch (m_out->m_lc_vfs_fcntl.cmd) {
647 	case F_GETFD:
648 		if (failed)
649 			break;
650 		put_fd_flags(proc, NULL, m_in->m_type);
651 		return;
652 	case F_GETFL:
653 		if (failed)
654 			break;
655 		put_open_flags(proc, NULL, m_in->m_type, TRUE /*full*/);
656 		return;
657 	case F_GETLK:
658 		put_struct_flock(proc, "lkp", failed | PF_FULL,
659 		    m_out->m_lc_vfs_fcntl.arg_ptr);
660 		put_equals(proc);
661 		break;
662 	}
663 
664 	put_result(proc);
665 }
666 
667 static int
668 vfs_pipe2_out(struct trace_proc * __unused proc,
669 	const message * __unused m_out)
670 {
671 
672 	return CT_NOTDONE;
673 }
674 
675 static void
676 vfs_pipe2_in(struct trace_proc * proc, const message * m_out,
677 	const message * m_in, int failed)
678 {
679 
680 	if (!failed) {
681 		put_open(proc, "fd", PF_NONAME, "[", ", ");
682 		put_fd(proc, "rfd", m_in->m_lc_vfs_pipe2.fd0);
683 		put_fd(proc, "wfd", m_in->m_lc_vfs_pipe2.fd1);
684 		put_close(proc, "]");
685 	} else
686 		put_field(proc, "fd", "&..");
687 	put_open_flags(proc, "flags", m_out->m_lc_vfs_pipe2.flags,
688 	    FALSE /*full*/);
689 	put_equals(proc);
690 	put_result(proc);
691 }
692 
693 static int
694 vfs_umask_out(struct trace_proc * proc, const message * m_out)
695 {
696 
697 	put_mode(proc, NULL, m_out->m_lc_vfs_umask.mask);
698 
699 	return CT_DONE;
700 }
701 
702 static void
703 vfs_umask_in(struct trace_proc * proc, const message * __unused m_out,
704 	const message * m_in, int failed)
705 {
706 
707 	if (!failed)
708 		put_mode(proc, NULL, m_in->m_type);
709 	else
710 		put_result(proc);
711 
712 }
713 
714 static void
715 put_dirent_type(struct trace_proc * proc, const char * name, unsigned int type)
716 {
717 	const char *text = NULL;
718 
719 	if (!valuesonly) {
720 		switch (type) {
721 		TEXT(DT_UNKNOWN);
722 		TEXT(DT_FIFO);
723 		TEXT(DT_CHR);
724 		TEXT(DT_DIR);
725 		TEXT(DT_BLK);
726 		TEXT(DT_REG);
727 		TEXT(DT_LNK);
728 		TEXT(DT_SOCK);
729 		TEXT(DT_WHT);
730 		}
731 	}
732 
733 	if (text != NULL)
734 		put_field(proc, name, text);
735 	else
736 		put_value(proc, name, "%u", type);
737 }
738 
739 static void
740 put_struct_dirent(struct trace_proc * proc, const char *name, int flags,
741 	vir_bytes addr)
742 {
743 	struct dirent dirent;
744 
745 	if (!put_open_struct(proc, name, flags, addr, &dirent, sizeof(dirent)))
746 		return;
747 
748 	if (verbose > 0)
749 		put_value(proc, "d_fileno", "%"PRIu64, dirent.d_fileno);
750 	if (verbose > 1) {
751 		put_value(proc, "d_reclen", "%u", dirent.d_reclen);
752 		put_value(proc, "d_namlen", "%u", dirent.d_namlen);
753 	}
754 	if (verbose >= 1 + (dirent.d_type == DT_UNKNOWN))
755 		put_dirent_type(proc, "d_type", dirent.d_type);
756 	put_buf(proc, "d_name", PF_LOCADDR, (vir_bytes)dirent.d_name,
757 	    MIN(dirent.d_namlen, sizeof(dirent.d_name)));
758 
759 	put_close_struct(proc, verbose > 1);
760 }
761 
762 static void
763 put_dirent_array(struct trace_proc * proc, const char * name, int flags,
764 	vir_bytes addr, ssize_t size)
765 {
766 	struct dirent dirent;
767 	unsigned count, max;
768 	ssize_t off, chunk;
769 
770 	if ((flags & PF_FAILED) || valuesonly > 1 || size < 0) {
771 		put_ptr(proc, name, addr);
772 
773 		return;
774 	}
775 
776 	if (size == 0) {
777 		put_field(proc, name, "[]");
778 
779 		return;
780 	}
781 
782 	if (verbose == 0)
783 		max = 0; /* TODO: should we set this to 1 instead? */
784 	else if (verbose == 1)
785 		max = 3; /* low; just to give an indication where we are */
786 	else
787 		max = INT_MAX;
788 
789 	/*
790 	 * TODO: as is, this is highly inefficient, as we are typically copying
791 	 * in the same pieces of memory in repeatedly..
792 	 */
793 	count = 0;
794 	for (off = 0; off < size; off += chunk) {
795 		chunk = size - off;
796 		if (chunk > sizeof(dirent))
797 			chunk = sizeof(dirent);
798 		if (chunk < _DIRENT_MINSIZE(&dirent))
799 			break;
800 
801 		if (mem_get_data(proc->pid, addr + off, &dirent, chunk) < 0) {
802 			if (off == 0) {
803 				put_ptr(proc, name, addr);
804 
805 				return;
806 			}
807 
808 			break;
809 		}
810 
811 		if (off == 0)
812 			put_open(proc, name, PF_NONAME, "[", ", ");
813 
814 		if (count < max)
815 			put_struct_dirent(proc, NULL, PF_LOCADDR,
816 			    (vir_bytes)&dirent);
817 
818 		if (chunk > dirent.d_reclen)
819 			chunk = dirent.d_reclen;
820 		count++;
821 	}
822 
823 	if (off < size)
824 		put_tail(proc, 0, 0);
825 	else if (count > max)
826 		put_tail(proc, count, max);
827 	put_close(proc, "]");
828 }
829 
830 static int
831 vfs_getdents_out(struct trace_proc * proc, const message * m_out)
832 {
833 
834 	put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
835 
836 	return CT_NOTDONE;
837 }
838 
839 static void
840 vfs_getdents_in(struct trace_proc * proc, const message * m_out,
841 	const message * m_in, int failed)
842 {
843 
844 	put_dirent_array(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf,
845 	    m_in->m_type);
846 	put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
847 	put_equals(proc);
848 	put_result(proc);
849 }
850 
851 static void
852 put_fd_set(struct trace_proc * proc, const char * name, vir_bytes addr,
853 	int nfds)
854 {
855 	fd_set set;
856 	size_t off;
857 	unsigned int i, j, words, count, max;
858 
859 	if (addr == 0 || nfds < 0) {
860 		put_ptr(proc, name, addr);
861 
862 		return;
863 	}
864 
865 	/*
866 	 * Each process may define its own FD_SETSIZE, so our fd_set may be of
867 	 * a different size than theirs.  Thus, we copy at a granularity known
868 	 * to be valid in any case: a single word of bits.  We make the
869 	 * assumption that fd_set consists purely of bits, so that we can use
870 	 * the second (and so on) bit word as an fd_set by itself.
871 	 */
872 	words = (nfds + NFDBITS - 1) / NFDBITS;
873 
874 	count = 0;
875 
876 	if (verbose == 0)
877 		max = 16;
878 	else if (verbose == 1)
879 		max = FD_SETSIZE;
880 	else
881 		max = INT_MAX;
882 
883 	/* TODO: copy in more at once, but stick to fd_mask boundaries. */
884 	for (off = 0, i = 0; i < words; i++, off += sizeof(fd_mask)) {
885 		if (mem_get_data(proc->pid, addr + off, &set,
886 		    sizeof(fd_mask)) != 0) {
887 			if (count == 0) {
888 				put_ptr(proc, name, addr);
889 
890 				return;
891 			}
892 
893 			break;
894 		}
895 
896 		for (j = 0; j < NFDBITS; j++) {
897 			if (FD_ISSET(j, &set)) {
898 				if (count == 0)
899 					put_open(proc, name, PF_NONAME, "[",
900 					    " ");
901 
902 				if (count < max)
903 					put_fd(proc, NULL, i * NFDBITS + j);
904 
905 				count++;
906 			}
907 		}
908 	}
909 
910 	/*
911 	 * The empty set should print as "[]".  If copying any part failed, it
912 	 * should print as "[x, ..(?)]" where x is the set printed so far, if
913 	 * any.  If copying never failed, and we did not print all fds in the
914 	 * set, print the remaining count n as "[x, ..(+n)]" at the end.
915 	 */
916 	if (count == 0)
917 		put_open(proc, name, PF_NONAME, "[", " ");
918 
919 	if (i < words)
920 		put_tail(proc, 0, 0);
921 	else if (count > max)
922 		put_tail(proc, count, max);
923 
924 	put_close(proc, "]");
925 }
926 
927 static int
928 vfs_select_out(struct trace_proc * proc, const message * m_out)
929 {
930 	int nfds;
931 
932 	nfds = m_out->m_lc_vfs_select.nfds;
933 
934 	put_fd(proc, "nfds", nfds); /* not really a file descriptor.. */
935 	put_fd_set(proc, "readfds",
936 	    (vir_bytes)m_out->m_lc_vfs_select.readfds, nfds);
937 	put_fd_set(proc, "writefds",
938 	    (vir_bytes)m_out->m_lc_vfs_select.writefds, nfds);
939 	put_fd_set(proc, "errorfds",
940 	    (vir_bytes)m_out->m_lc_vfs_select.errorfds, nfds);
941 	put_struct_timeval(proc, "timeout", 0, m_out->m_lc_vfs_select.timeout);
942 
943 	return CT_DONE;
944 }
945 
946 static void
947 vfs_select_in(struct trace_proc * proc, const message * m_out,
948 	const message * __unused m_in, int failed)
949 {
950 	vir_bytes readfds, writefds, errorfds;
951 	int nfds;
952 
953 	put_result(proc);
954 	if (failed)
955 		return;
956 
957 	nfds = m_out->m_lc_vfs_select.nfds;
958 
959 	readfds = (vir_bytes)m_out->m_lc_vfs_select.readfds;
960 	writefds = (vir_bytes)m_out->m_lc_vfs_select.writefds;
961 	errorfds = (vir_bytes)m_out->m_lc_vfs_select.errorfds;
962 
963 	if (readfds == 0 && writefds == 0 && errorfds == 0)
964 		return;
965 
966 	/* Omit names, because it looks weird. */
967 	put_open(proc, NULL, PF_NONAME, "(", ", ");
968 	if (readfds != 0)
969 		put_fd_set(proc, "readfds", readfds, nfds);
970 	if (writefds != 0)
971 		put_fd_set(proc, "writefds", writefds, nfds);
972 	if (errorfds != 0)
973 		put_fd_set(proc, "errorfds", errorfds, nfds);
974 	put_close(proc, ")");
975 }
976 
977 static int
978 vfs_fchdir_out(struct trace_proc * proc, const message * m_out)
979 {
980 
981 	put_fd(proc, "fd", m_out->m_lc_vfs_fchdir.fd);
982 
983 	return CT_DONE;
984 }
985 
986 static int
987 vfs_fsync_out(struct trace_proc * proc, const message * m_out)
988 {
989 
990 	put_fd(proc, "fd", m_out->m_lc_vfs_fsync.fd);
991 
992 	return CT_DONE;
993 }
994 
995 static int
996 vfs_truncate_out(struct trace_proc * proc, const message * m_out)
997 {
998 
999 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_truncate.name,
1000 	    m_out->m_lc_vfs_truncate.len);
1001 	put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1002 
1003 	return CT_DONE;
1004 }
1005 
1006 static int
1007 vfs_ftruncate_out(struct trace_proc * proc, const message * m_out)
1008 {
1009 
1010 	put_fd(proc, "fd", m_out->m_lc_vfs_truncate.fd);
1011 	put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1012 
1013 	return CT_DONE;
1014 }
1015 
1016 static int
1017 vfs_fchmod_out(struct trace_proc * proc, const message * m_out)
1018 {
1019 
1020 	put_fd(proc, "fd", m_out->m_lc_vfs_fchmod.fd);
1021 	put_mode(proc, "mode", m_out->m_lc_vfs_fchmod.mode);
1022 
1023 	return CT_DONE;
1024 }
1025 
1026 static int
1027 vfs_fchown_out(struct trace_proc * proc, const message * m_out)
1028 {
1029 
1030 	put_fd(proc, "fd", m_out->m_lc_vfs_chown.fd);
1031 	/* -1 means "keep the current value" so print as signed */
1032 	put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner);
1033 	put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group);
1034 
1035 	return CT_DONE;
1036 }
1037 
1038 static const char *
1039 vfs_utimens_name(const message * m_out)
1040 {
1041 	int has_path, has_flags;
1042 
1043 	has_path = (m_out->m_vfs_utimens.name != NULL);
1044 	has_flags = (m_out->m_vfs_utimens.flags != 0);
1045 
1046 	if (has_path && m_out->m_vfs_utimens.flags == AT_SYMLINK_NOFOLLOW)
1047 		return "lutimens";
1048 	if (has_path && !has_flags)
1049 		return "utimens";
1050 	else if (!has_path && !has_flags)
1051 		return "futimens";
1052 	else
1053 		return "utimensat";
1054 }
1055 
1056 static const struct flags at_flags[] = {
1057 	FLAG(AT_EACCESS),
1058 	FLAG(AT_SYMLINK_NOFOLLOW),
1059 	FLAG(AT_SYMLINK_FOLLOW),
1060 	FLAG(AT_REMOVEDIR),
1061 };
1062 
1063 static void
1064 put_utimens_timespec(struct trace_proc * proc, const char * name,
1065 	time_t sec, long nsec)
1066 {
1067 
1068 	/* No field names. */
1069 	put_open(proc, name, PF_NONAME, "{", ", ");
1070 
1071 	put_time(proc, "tv_sec", sec);
1072 
1073 	if (!valuesonly && nsec == UTIME_NOW)
1074 		put_field(proc, "tv_nsec", "UTIME_NOW");
1075 	else if (!valuesonly && nsec == UTIME_OMIT)
1076 		put_field(proc, "tv_nsec", "UTIME_OMIT");
1077 	else
1078 		put_value(proc, "tv_nsec", "%ld", nsec);
1079 
1080 	put_close(proc, "}");
1081 }
1082 
1083 static int
1084 vfs_utimens_out(struct trace_proc * proc, const message * m_out)
1085 {
1086 	int has_path, has_flags;
1087 
1088 	/* Here we do not care about the utimens/lutimens distinction. */
1089 	has_path = (m_out->m_vfs_utimens.name != NULL);
1090 	has_flags = !!(m_out->m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW);
1091 
1092 	if (has_path && has_flags)
1093 		put_field(proc, "fd", "AT_CWD"); /* utimensat */
1094 	else if (!has_path)
1095 		put_fd(proc, "fd", m_out->m_vfs_utimens.fd); /* futimes */
1096 	if (has_path || has_flags) /* lutimes, utimes, utimensat */
1097 		put_buf(proc, "path", PF_PATH,
1098 		    (vir_bytes)m_out->m_vfs_utimens.name,
1099 		    m_out->m_vfs_utimens.len);
1100 
1101 	put_open(proc, "times", 0, "[", ", ");
1102 	put_utimens_timespec(proc, "atime", m_out->m_vfs_utimens.atime,
1103 	    m_out->m_vfs_utimens.ansec);
1104 	put_utimens_timespec(proc, "mtime", m_out->m_vfs_utimens.mtime,
1105 	    m_out->m_vfs_utimens.mnsec);
1106 	put_close(proc, "]");
1107 
1108 	if (has_flags)
1109 		put_flags(proc, "flag", at_flags, COUNT(at_flags), "0x%x",
1110 		    m_out->m_vfs_utimens.flags);
1111 
1112 	return CT_DONE;
1113 }
1114 
1115 static const struct flags statvfs_flags[] = {
1116 	FLAG(ST_WAIT),
1117 	FLAG(ST_NOWAIT),
1118 };
1119 
1120 static const struct flags st_flags[] = {
1121 	FLAG(ST_RDONLY),
1122 	FLAG(ST_SYNCHRONOUS),
1123 	FLAG(ST_NOEXEC),
1124 	FLAG(ST_NOSUID),
1125 	FLAG(ST_NODEV),
1126 	FLAG(ST_UNION),
1127 	FLAG(ST_ASYNC),
1128 	FLAG(ST_NOCOREDUMP),
1129 	FLAG(ST_RELATIME),
1130 	FLAG(ST_IGNORE),
1131 	FLAG(ST_NOATIME),
1132 	FLAG(ST_SYMPERM),
1133 	FLAG(ST_NODEVMTIME),
1134 	FLAG(ST_SOFTDEP),
1135 	FLAG(ST_LOG),
1136 	FLAG(ST_EXTATTR),
1137 	FLAG(ST_EXRDONLY),
1138 	FLAG(ST_EXPORTED),
1139 	FLAG(ST_DEFEXPORTED),
1140 	FLAG(ST_EXPORTANON),
1141 	FLAG(ST_EXKERB),
1142 	FLAG(ST_EXNORESPORT),
1143 	FLAG(ST_EXPUBLIC),
1144 	FLAG(ST_LOCAL),
1145 	FLAG(ST_QUOTA),
1146 	FLAG(ST_ROOTFS),
1147 	FLAG(ST_NOTRUNC),
1148 };
1149 
1150 static void
1151 put_struct_statvfs(struct trace_proc * proc, const char * name, int flags,
1152 	vir_bytes addr)
1153 {
1154 	struct statvfs buf;
1155 
1156 	if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
1157 		return;
1158 
1159 	put_flags(proc, "f_flag", st_flags, COUNT(st_flags), "0x%x",
1160 	    buf.f_flag);
1161 	put_value(proc, "f_bsize", "%lu", buf.f_bsize);
1162 	if (verbose > 0 || buf.f_bsize != buf.f_frsize)
1163 		put_value(proc, "f_frsize", "%lu", buf.f_frsize);
1164 	if (verbose > 1)
1165 		put_value(proc, "f_iosize", "%lu", buf.f_iosize);
1166 
1167 	put_value(proc, "f_blocks", "%"PRIu64, buf.f_blocks);
1168 	put_value(proc, "f_bfree", "%"PRIu64, buf.f_bfree);
1169 	if (verbose > 1) {
1170 		put_value(proc, "f_bavail", "%"PRIu64, buf.f_bavail);
1171 		put_value(proc, "f_bresvd", "%"PRIu64, buf.f_bresvd);
1172 	}
1173 
1174 	if (verbose > 0) {
1175 		put_value(proc, "f_files", "%"PRIu64, buf.f_files);
1176 		put_value(proc, "f_ffree", "%"PRIu64, buf.f_ffree);
1177 	}
1178 	if (verbose > 1) {
1179 		put_value(proc, "f_favail", "%"PRIu64, buf.f_favail);
1180 		put_value(proc, "f_fresvd", "%"PRIu64, buf.f_fresvd);
1181 	}
1182 
1183 	if (verbose > 1) {
1184 		put_value(proc, "f_syncreads", "%"PRIu64, buf.f_syncreads);
1185 		put_value(proc, "f_syncwrites", "%"PRIu64, buf.f_syncwrites);
1186 		put_value(proc, "f_asyncreads", "%"PRIu64, buf.f_asyncreads);
1187 		put_value(proc, "f_asyncwrites", "%"PRIu64, buf.f_asyncwrites);
1188 
1189 		put_value(proc, "f_fsidx", "<%"PRId32",%"PRId32">",
1190 		    buf.f_fsidx.__fsid_val[0], buf.f_fsidx.__fsid_val[1]);
1191 	}
1192 	put_dev(proc, "f_fsid", buf.f_fsid); /* MINIX3 interpretation! */
1193 
1194 	if (verbose > 0)
1195 		put_value(proc, "f_namemax", "%lu", buf.f_namemax);
1196 	if (verbose > 1)
1197 		put_value(proc, "f_owner", "%u", buf.f_owner);
1198 
1199 	put_buf(proc, "f_fstypename", PF_STRING | PF_LOCADDR,
1200 	    (vir_bytes)&buf.f_fstypename, sizeof(buf.f_fstypename));
1201 	if (verbose > 0)
1202 		put_buf(proc, "f_mntfromname", PF_STRING | PF_LOCADDR,
1203 		    (vir_bytes)&buf.f_mntfromname, sizeof(buf.f_mntfromname));
1204 	put_buf(proc, "f_mntonname", PF_STRING | PF_LOCADDR,
1205 	    (vir_bytes)&buf.f_mntonname, sizeof(buf.f_mntonname));
1206 
1207 	put_close_struct(proc, verbose > 1);
1208 }
1209 
1210 static void
1211 put_statvfs_array(struct trace_proc * proc, const char * name, int flags,
1212 	vir_bytes addr, int count)
1213 {
1214 	struct statvfs buf;
1215 	int i, max;
1216 
1217 	if ((flags & PF_FAILED) || valuesonly || count < 0) {
1218 		put_ptr(proc, name, addr);
1219 
1220 		return;
1221 	}
1222 
1223 	if (count == 0) {
1224 		put_field(proc, name, "[]");
1225 
1226 		return;
1227 	}
1228 
1229 	if (verbose == 0)
1230 		max = 0;
1231 	else if (verbose == 1)
1232 		max = 1; /* TODO: is this reasonable? */
1233 	else
1234 		max = INT_MAX;
1235 
1236 	if (max > count)
1237 		max = count;
1238 
1239 	for (i = 0; i < max; i++) {
1240 		if (mem_get_data(proc->pid, addr + i * sizeof(buf), &buf,
1241 		    sizeof(buf)) < 0) {
1242 			if (i == 0) {
1243 				put_ptr(proc, name, addr);
1244 
1245 				return;
1246 			}
1247 
1248 			break;
1249 		}
1250 
1251 		if (i == 0)
1252 			put_open(proc, name, PF_NONAME, "[", ", ");
1253 
1254 		put_struct_statvfs(proc, NULL, PF_LOCADDR, (vir_bytes)&buf);
1255 	}
1256 
1257 	if (i == 0)
1258 		put_open(proc, name, PF_NONAME, "[", ", ");
1259 	if (i < max)
1260 		put_tail(proc, 0, 0);
1261 	else if (count > i)
1262 		put_tail(proc, count, i);
1263 	put_close(proc, "]");
1264 }
1265 
1266 static int
1267 vfs_getvfsstat_out(struct trace_proc * proc, const message * m_out)
1268 {
1269 
1270 	if (m_out->m_lc_vfs_getvfsstat.buf == 0) {
1271 		put_ptr(proc, "buf", m_out->m_lc_vfs_getvfsstat.buf);
1272 		put_value(proc, "bufsize", "%zu",
1273 		    m_out->m_lc_vfs_getvfsstat.len);
1274 		put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1275 		    "%d", m_out->m_lc_vfs_getvfsstat.flags);
1276 		return CT_DONE;
1277 	} else
1278 		return CT_NOTDONE;
1279 }
1280 
1281 static void
1282 vfs_getvfsstat_in(struct trace_proc * proc, const message * m_out,
1283 	const message * m_in, int failed)
1284 {
1285 
1286 	if (m_out->m_lc_vfs_getvfsstat.buf != 0) {
1287 		put_statvfs_array(proc, "buf", failed,
1288 		    m_out->m_lc_vfs_getvfsstat.buf, m_in->m_type);
1289 		put_value(proc, "bufsize", "%zu",
1290 		    m_out->m_lc_vfs_getvfsstat.len);
1291 		put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1292 		    "%d", m_out->m_lc_vfs_getvfsstat.flags);
1293 		put_equals(proc);
1294 	}
1295 	put_result(proc);
1296 }
1297 
1298 static int
1299 vfs_statvfs1_out(struct trace_proc * proc, const message * m_out)
1300 {
1301 
1302 	put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_statvfs1.name,
1303 	    m_out->m_lc_vfs_statvfs1.len);
1304 
1305 	return CT_NOTDONE;
1306 }
1307 
1308 static void
1309 vfs_statvfs1_in(struct trace_proc * proc, const message * m_out,
1310 	const message * __unused m_in, int failed)
1311 {
1312 
1313 	put_struct_statvfs(proc, "buf", failed, m_out->m_lc_vfs_statvfs1.buf);
1314 	put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), "%d",
1315 	    m_out->m_lc_vfs_statvfs1.flags);
1316 	put_equals(proc);
1317 	put_result(proc);
1318 }
1319 
1320 /* This function is shared between statvfs1 and fstatvfs1. */
1321 static int
1322 vfs_fstatvfs1_out(struct trace_proc * proc, const message * m_out)
1323 {
1324 
1325 	put_fd(proc, "fd", m_out->m_lc_vfs_statvfs1.fd);
1326 
1327 	return CT_NOTDONE;
1328 }
1329 
1330 static int
1331 vfs_svrctl_out(struct trace_proc * proc, const message * m_out)
1332 {
1333 
1334 	put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request,
1335 	    TRUE /*is_svrctl*/);
1336 	return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request,
1337 	    m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1338 }
1339 
1340 static void
1341 vfs_svrctl_in(struct trace_proc * proc, const message * m_out,
1342 	const message * __unused m_in, int failed)
1343 {
1344 
1345 	put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request,
1346 	    m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1347 }
1348 
1349 static int
1350 vfs_gcov_flush_out(struct trace_proc * proc, const message * m_out)
1351 {
1352 
1353 	put_ptr(proc, "buff", m_out->m_lc_vfs_gcov.buff_p);
1354 	put_value(proc, "buff_sz", "%zu", m_out->m_lc_vfs_gcov.buff_sz);
1355 	put_value(proc, "server_pid", "%d", m_out->m_lc_vfs_gcov.pid);
1356 
1357 	return CT_DONE;
1358 }
1359 
1360 #define VFS_CALL(c) [((VFS_ ## c) - VFS_BASE)]
1361 
1362 static const struct call_handler vfs_map[] = {
1363 	VFS_CALL(READ) = HANDLER("read", vfs_read_out, vfs_read_in),
1364 	VFS_CALL(WRITE) = HANDLER("write", vfs_write_out, default_in),
1365 	VFS_CALL(LSEEK) = HANDLER("lseek", vfs_lseek_out, vfs_lseek_in),
1366 	VFS_CALL(OPEN) = HANDLER("open", vfs_open_out, vfs_open_in),
1367 	VFS_CALL(CREAT) = HANDLER("open", vfs_creat_out, vfs_open_in),
1368 	VFS_CALL(CLOSE) = HANDLER("close", vfs_close_out, default_in),
1369 	VFS_CALL(LINK) = HANDLER("link", vfs_link_out, default_in),
1370 	VFS_CALL(UNLINK) = HANDLER("unlink", vfs_path_out, default_in),
1371 	VFS_CALL(CHDIR) = HANDLER("chdir", vfs_path_out, default_in),
1372 	VFS_CALL(MKDIR) = HANDLER("mkdir", vfs_path_mode_out, default_in),
1373 	VFS_CALL(MKNOD) = HANDLER("mknod", vfs_mknod_out, default_in),
1374 	VFS_CALL(CHMOD) = HANDLER("chmod", vfs_path_mode_out, default_in),
1375 	VFS_CALL(CHOWN) = HANDLER("chown", vfs_chown_out, default_in),
1376 	VFS_CALL(MOUNT) = HANDLER("mount", vfs_mount_out, default_in),
1377 	VFS_CALL(UMOUNT) = HANDLER("umount", vfs_umount_out, vfs_umount_in),
1378 	VFS_CALL(ACCESS) = HANDLER("access", vfs_access_out, default_in),
1379 	VFS_CALL(SYNC) = HANDLER("sync", default_out, default_in),
1380 	VFS_CALL(RENAME) = HANDLER("rename", vfs_link_out, default_in),
1381 	VFS_CALL(RMDIR) = HANDLER("rmdir", vfs_path_out, default_in),
1382 	VFS_CALL(SYMLINK) = HANDLER("symlink", vfs_link_out, default_in),
1383 	VFS_CALL(READLINK) = HANDLER("readlink", vfs_readlink_out,
1384 	    vfs_readlink_in),
1385 	VFS_CALL(STAT) = HANDLER("stat", vfs_stat_out, vfs_stat_in),
1386 	VFS_CALL(FSTAT) = HANDLER("fstat", vfs_fstat_out, vfs_fstat_in),
1387 	VFS_CALL(LSTAT) = HANDLER("lstat", vfs_stat_out, vfs_stat_in),
1388 	VFS_CALL(IOCTL) = HANDLER("ioctl", vfs_ioctl_out, vfs_ioctl_in),
1389 	VFS_CALL(FCNTL) = HANDLER("fcntl", vfs_fcntl_out, vfs_fcntl_in),
1390 	VFS_CALL(PIPE2) = HANDLER("pipe2", vfs_pipe2_out, vfs_pipe2_in),
1391 	VFS_CALL(UMASK) = HANDLER("umask", vfs_umask_out, vfs_umask_in),
1392 	VFS_CALL(CHROOT) = HANDLER("chroot", vfs_path_out, default_in),
1393 	VFS_CALL(GETDENTS) = HANDLER("getdents", vfs_getdents_out,
1394 	    vfs_getdents_in),
1395 	VFS_CALL(SELECT) = HANDLER("select", vfs_select_out, vfs_select_in),
1396 	VFS_CALL(FCHDIR) = HANDLER("fchdir", vfs_fchdir_out, default_in),
1397 	VFS_CALL(FSYNC) = HANDLER("fsync", vfs_fsync_out, default_in),
1398 	VFS_CALL(TRUNCATE) = HANDLER("truncate", vfs_truncate_out, default_in),
1399 	VFS_CALL(FTRUNCATE) = HANDLER("ftruncate", vfs_ftruncate_out,
1400 	    default_in),
1401 	VFS_CALL(FCHMOD) = HANDLER("fchmod", vfs_fchmod_out, default_in),
1402 	VFS_CALL(FCHOWN) = HANDLER("fchown", vfs_fchown_out, default_in),
1403 	VFS_CALL(UTIMENS) = HANDLER_NAME(vfs_utimens_name, vfs_utimens_out,
1404 	    default_in),
1405 	VFS_CALL(GETVFSSTAT) = HANDLER("getvfsstat", vfs_getvfsstat_out,
1406 	    vfs_getvfsstat_in),
1407 	VFS_CALL(STATVFS1) = HANDLER("statvfs1", vfs_statvfs1_out,
1408 	    vfs_statvfs1_in),
1409 	VFS_CALL(FSTATVFS1) = HANDLER("fstatvfs1", vfs_fstatvfs1_out,
1410 	    vfs_statvfs1_in),
1411 	VFS_CALL(SVRCTL) = HANDLER("vfs_svrctl", vfs_svrctl_out,
1412 	    vfs_svrctl_in),
1413 	VFS_CALL(GCOV_FLUSH) = HANDLER("gcov_flush", vfs_gcov_flush_out,
1414 	    default_in),
1415 };
1416 
1417 const struct calls vfs_calls = {
1418 	.endpt = VFS_PROC_NR,
1419 	.base = VFS_BASE,
1420 	.map = vfs_map,
1421 	.count = COUNT(vfs_map)
1422 };
1423