trace(1): resolve all level-5 LLVM warnings
[minix3.git] / minix / usr.bin / trace / service / vfs.c
blobc928f2e269ff6189a2ac8fe067919929b4911982
2 #include "inc.h"
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <dirent.h>
7 #include <sys/mount.h>
8 #include <sys/resource.h>
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).
15 void
16 put_fd(struct trace_proc * proc, const char * name, int fd)
19 put_value(proc, name, "%d", fd);
22 static int
23 vfs_read_out(struct trace_proc * proc, const message *m_out)
26 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
28 return CT_NOTDONE;
31 static void
32 vfs_read_in(struct trace_proc * proc, const message *m_out,
33 const message *m_in, int failed)
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);
43 static int
44 vfs_write_out(struct trace_proc * proc, const message *m_out)
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);
52 return CT_DONE;
55 static void
56 put_lseek_whence(struct trace_proc * proc, const char * name, int whence)
58 const char *text = NULL;
60 if (!valuesonly) {
61 switch (whence) {
62 TEXT(SEEK_SET);
63 TEXT(SEEK_CUR);
64 TEXT(SEEK_END);
68 if (text != NULL)
69 put_field(proc, name, text);
70 else
71 put_value(proc, name, "%d", whence);
74 static int
75 vfs_lseek_out(struct trace_proc * proc, const message * m_out)
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);
82 return CT_DONE;
85 static void
86 vfs_lseek_in(struct trace_proc * proc, const message * __unused m_out,
87 const message * m_in, int failed)
90 if (!failed)
91 put_value(proc, NULL, "%"PRId64, m_in->m_vfs_lc_lseek.offset);
92 else
93 put_result(proc);
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),
122 static void
123 put_open_flags(struct trace_proc * proc, const char * name, int value,
124 int full)
126 const struct flags *fp;
127 unsigned int num;
129 fp = open_flags;
130 num = COUNT(open_flags);
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.
137 if (!full) {
138 fp += ACCMODE_ENTRIES;
139 num -= ACCMODE_ENTRIES;
142 put_flags(proc, name, fp, num, "0x%x", value);
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),
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)
165 static void
166 put_path(struct trace_proc * proc, const message * m_out)
168 size_t len;
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);
177 static int
178 vfs_open_out(struct trace_proc * proc, const message * m_out)
181 put_path(proc, m_out);
182 put_open_flags(proc, "flags", m_out->m_lc_vfs_path.flags,
183 TRUE /*full*/);
185 return CT_DONE;
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)
194 if (!failed)
195 put_fd(proc, NULL, m_in->m_type);
196 else
197 put_result(proc);
200 static int
201 vfs_creat_out(struct trace_proc * proc, const message * m_out)
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);
210 return CT_DONE;
213 static int
214 vfs_close_out(struct trace_proc * proc, const message * m_out)
217 put_fd(proc, "fd", m_out->m_lc_vfs_close.fd);
219 return CT_DONE;
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)
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);
232 return CT_DONE;
235 static int
236 vfs_path_out(struct trace_proc * proc, const message * m_out)
239 put_path(proc, m_out);
241 return CT_DONE;
244 static int
245 vfs_path_mode_out(struct trace_proc * proc, const message * m_out)
248 put_path(proc, m_out);
249 put_mode(proc, "mode", m_out->m_lc_vfs_path.mode);
251 return CT_DONE;
254 void
255 put_dev(struct trace_proc * proc, const char * name, dev_t dev)
257 devmajor_t major;
258 devminor_t minor;
260 major = major(dev);
261 minor = minor(dev);
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);
270 static int
271 vfs_mknod_out(struct trace_proc * proc, const message * m_out)
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);
279 return CT_DONE;
282 static int
283 vfs_chown_out(struct trace_proc * proc, const message * m_out)
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);
292 return CT_DONE;
295 /* TODO: expand this to the full ST_ set. */
296 static const struct flags mount_flags[] = {
297 FLAG(MNT_RDONLY),
300 static int
301 vfs_mount_out(struct trace_proc * proc, const message * m_out)
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);
315 return CT_DONE;
318 static int
319 vfs_umount_out(struct trace_proc * proc, const message * m_out)
322 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_umount.name,
323 m_out->m_lc_vfs_umount.namelen);
325 return CT_DONE;
328 static void
329 vfs_umount_in(struct trace_proc * proc, const message * m_out,
330 const message * __unused m_in, int failed)
333 put_result(proc);
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);
340 put_close(proc, ")");
345 static const struct flags access_flags[] = {
346 FLAG_ZERO(F_OK),
347 FLAG(R_OK),
348 FLAG(W_OK),
349 FLAG(X_OK),
352 static int
353 vfs_access_out(struct trace_proc * proc, const message * m_out)
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);
360 return CT_DONE;
363 static int
364 vfs_readlink_out(struct trace_proc * proc, const message * m_out)
367 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_readlink.name,
368 m_out->m_lc_vfs_readlink.namelen);
370 return CT_NOTDONE;
373 static void
374 vfs_readlink_in(struct trace_proc * proc, const message * m_out,
375 const message * m_in, int failed)
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);
386 static void
387 put_struct_stat(struct trace_proc * proc, const char * name, int flags,
388 vir_bytes addr)
390 struct stat buf;
391 int is_special;
393 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
394 return;
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.
409 is_special = (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
411 if (verbose > 0) {
412 put_dev(proc, "st_dev", buf.st_dev);
413 put_value(proc, "st_ino", "%"PRId64, buf.st_ino);
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);
421 if (is_special || verbose > 1)
422 put_dev(proc, "st_rdev", buf.st_rdev);
423 if (verbose > 0) {
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).
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);
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);
441 if (verbose > 1) {
442 put_value(proc, "st_flags", "%"PRIu32, buf.st_flags);
443 put_value(proc, "st_gen", "%"PRIu32, buf.st_gen);
446 put_close_struct(proc, verbose > 1);
449 static int
450 vfs_stat_out(struct trace_proc * proc, const message * m_out)
453 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_stat.name,
454 m_out->m_lc_vfs_stat.len);
456 return CT_NOTDONE;
459 static void
460 vfs_stat_in(struct trace_proc * proc, const message * m_out,
461 const message * __unused m_in, int failed)
464 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_stat.buf);
465 put_equals(proc);
466 put_result(proc);
469 static int
470 vfs_fstat_out(struct trace_proc * proc, const message * m_out)
473 put_fd(proc, "fd", m_out->m_lc_vfs_fstat.fd);
475 return CT_NOTDONE;
478 static void
479 vfs_fstat_in(struct trace_proc * proc, const message * m_out,
480 const message * __unused m_in, int failed)
483 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_fstat.buf);
484 put_equals(proc);
485 put_result(proc);
488 static int
489 vfs_ioctl_out(struct trace_proc * proc, const message * m_out)
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*/);
499 static void
500 vfs_ioctl_in(struct trace_proc * proc, const message * m_out,
501 const message * __unused m_in, int failed)
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*/);
508 static void
509 put_fcntl_cmd(struct trace_proc * proc, const char * name, int cmd)
511 const char *text = NULL;
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);
535 if (text != NULL)
536 put_field(proc, name, text);
537 else
538 put_value(proc, name, "%d", cmd);
541 static const struct flags fd_flags[] = {
542 FLAG(FD_CLOEXEC),
545 #define put_fd_flags(p, n, v) \
546 put_flags(p, n, fd_flags, COUNT(fd_flags), "0x%x", v)
548 static void
549 put_flock_type(struct trace_proc * proc, const char * name, int type)
551 const char *text = NULL;
553 if (!valuesonly) {
554 switch (type) {
555 TEXT(F_RDLCK);
556 TEXT(F_UNLCK);
557 TEXT(F_WRLCK);
561 if (text != NULL)
562 put_field(proc, name, text);
563 else
564 put_value(proc, name, "%d", type);
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.
571 static void
572 put_struct_flock(struct trace_proc * proc, const char * name, int flags,
573 vir_bytes addr)
575 struct flock flock;
576 int limited;
578 if (!put_open_struct(proc, name, flags, addr, &flock, sizeof(flock)))
579 return;
581 limited = ((flags & PF_FULL) && flock.l_type == F_UNLCK);
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);
593 put_close_struct(proc, TRUE /*all*/);
596 static int
597 vfs_fcntl_out(struct trace_proc * proc, const message * m_out)
600 put_fd(proc, "fd", m_out->m_lc_vfs_fcntl.fd);
601 put_fcntl_cmd(proc, "cmd", m_out->m_lc_vfs_fcntl.cmd);
603 switch (m_out->m_lc_vfs_fcntl.cmd) {
604 case F_DUPFD:
605 case F_DUPFD_CLOEXEC:
606 put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int);
607 break;
608 case F_SETFD:
609 put_fd_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int);
610 break;
611 case F_SETFL:
613 * One of those difficult cases: the access mode is ignored, so
614 * we don't want to print O_RDONLY if it is not given. On the
615 * other hand, fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_..) is
616 * a fairly common construction, in which case we don't want to
617 * print eg O_..|0x2 if the access mode is O_RDWR. Thus, we
618 * compromise: show the access mode if any of its bits are set.
620 put_open_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int,
621 m_out->m_lc_vfs_fcntl.arg_int & O_ACCMODE /*full*/);
622 break;
623 case F_SETLK:
624 case F_SETLKW:
625 put_struct_flock(proc, "lkp", 0,
626 m_out->m_lc_vfs_fcntl.arg_ptr);
627 break;
628 case F_FREESP:
629 put_struct_flock(proc, "lkp", PF_ALT,
630 m_out->m_lc_vfs_fcntl.arg_ptr);
631 break;
632 case F_SETNOSIGPIPE:
633 put_value(proc, "arg", "%d", m_out->m_lc_vfs_fcntl.arg_int);
634 break;
637 return (m_out->m_lc_vfs_fcntl.cmd != F_GETLK) ? CT_DONE : CT_NOTDONE;
640 static void
641 vfs_fcntl_in(struct trace_proc * proc, const message * m_out,
642 const message * m_in, int failed)
645 switch (m_out->m_lc_vfs_fcntl.cmd) {
646 case F_GETFD:
647 if (failed)
648 break;
649 put_fd_flags(proc, NULL, m_in->m_type);
650 return;
651 case F_GETFL:
652 if (failed)
653 break;
654 put_open_flags(proc, NULL, m_in->m_type, TRUE /*full*/);
655 return;
656 case F_GETLK:
657 put_struct_flock(proc, "lkp", failed | PF_FULL,
658 m_out->m_lc_vfs_fcntl.arg_ptr);
659 put_equals(proc);
660 break;
663 put_result(proc);
666 static int
667 vfs_pipe2_out(struct trace_proc * __unused proc,
668 const message * __unused m_out)
671 return CT_NOTDONE;
674 static void
675 vfs_pipe2_in(struct trace_proc * proc, const message * m_out,
676 const message * m_in, int failed)
679 if (!failed) {
680 put_open(proc, "fd", PF_NONAME, "[", ", ");
681 put_fd(proc, "rfd", m_in->m_lc_vfs_pipe2.fd0);
682 put_fd(proc, "wfd", m_in->m_lc_vfs_pipe2.fd1);
683 put_close(proc, "]");
684 } else
685 put_field(proc, "fd", "&..");
686 put_open_flags(proc, "flags", m_out->m_lc_vfs_pipe2.flags,
687 FALSE /*full*/);
688 put_equals(proc);
689 put_result(proc);
692 static int
693 vfs_umask_out(struct trace_proc * proc, const message * m_out)
696 put_mode(proc, NULL, m_out->m_lc_vfs_umask.mask);
698 return CT_DONE;
701 static void
702 vfs_umask_in(struct trace_proc * proc, const message * __unused m_out,
703 const message * m_in, int failed)
706 if (!failed)
707 put_mode(proc, NULL, m_in->m_type);
708 else
709 put_result(proc);
713 static void
714 put_dirent_type(struct trace_proc * proc, const char * name, unsigned int type)
716 const char *text = NULL;
718 if (!valuesonly) {
719 switch (type) {
720 TEXT(DT_UNKNOWN);
721 TEXT(DT_FIFO);
722 TEXT(DT_CHR);
723 TEXT(DT_DIR);
724 TEXT(DT_BLK);
725 TEXT(DT_REG);
726 TEXT(DT_LNK);
727 TEXT(DT_SOCK);
728 TEXT(DT_WHT);
732 if (text != NULL)
733 put_field(proc, name, text);
734 else
735 put_value(proc, name, "%u", type);
738 static void
739 put_struct_dirent(struct trace_proc * proc, const char *name, int flags,
740 vir_bytes addr)
742 struct dirent dirent;
744 if (!put_open_struct(proc, name, flags, addr, &dirent, sizeof(dirent)))
745 return;
747 if (verbose > 0)
748 put_value(proc, "d_fileno", "%"PRIu64, dirent.d_fileno);
749 if (verbose > 1) {
750 put_value(proc, "d_reclen", "%u", dirent.d_reclen);
751 put_value(proc, "d_namlen", "%u", dirent.d_namlen);
753 if (verbose >= 1 + (dirent.d_type == DT_UNKNOWN))
754 put_dirent_type(proc, "d_type", dirent.d_type);
755 put_buf(proc, "d_name", PF_LOCADDR, (vir_bytes)dirent.d_name,
756 MIN(dirent.d_namlen, sizeof(dirent.d_name)));
758 put_close_struct(proc, verbose > 1);
761 static void
762 put_dirent_array(struct trace_proc * proc, const char * name, int flags,
763 vir_bytes addr, ssize_t size)
765 struct dirent dirent;
766 unsigned count, max;
767 ssize_t off, chunk;
769 if ((flags & PF_FAILED) || valuesonly > 1 || size < 0) {
770 put_ptr(proc, name, addr);
772 return;
775 if (size == 0) {
776 put_field(proc, name, "[]");
778 return;
781 if (verbose == 0)
782 max = 0; /* TODO: should we set this to 1 instead? */
783 else if (verbose == 1)
784 max = 3; /* low; just to give an indication where we are */
785 else
786 max = INT_MAX;
789 * TODO: as is, this is highly inefficient, as we are typically copying
790 * in the same pieces of memory in repeatedly..
792 count = 0;
793 for (off = 0; off < size; off += chunk) {
794 chunk = size - off;
795 if ((size_t)chunk > sizeof(dirent))
796 chunk = (ssize_t)sizeof(dirent);
797 if ((size_t)chunk < _DIRENT_MINSIZE(&dirent))
798 break;
800 if (mem_get_data(proc->pid, addr + off, &dirent, chunk) < 0) {
801 if (off == 0) {
802 put_ptr(proc, name, addr);
804 return;
807 break;
810 if (off == 0)
811 put_open(proc, name, PF_NONAME, "[", ", ");
813 if (count < max)
814 put_struct_dirent(proc, NULL, PF_LOCADDR,
815 (vir_bytes)&dirent);
817 if (chunk > dirent.d_reclen)
818 chunk = dirent.d_reclen;
819 count++;
822 if (off < size)
823 put_tail(proc, 0, 0);
824 else if (count > max)
825 put_tail(proc, count, max);
826 put_close(proc, "]");
829 static int
830 vfs_getdents_out(struct trace_proc * proc, const message * m_out)
833 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
835 return CT_NOTDONE;
838 static void
839 vfs_getdents_in(struct trace_proc * proc, const message * m_out,
840 const message * m_in, int failed)
843 put_dirent_array(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf,
844 m_in->m_type);
845 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
846 put_equals(proc);
847 put_result(proc);
850 static void
851 put_fd_set(struct trace_proc * proc, const char * name, vir_bytes addr,
852 int nfds)
854 fd_set set;
855 size_t off;
856 unsigned int i, j, words, count, max;
858 if (addr == 0 || nfds < 0) {
859 put_ptr(proc, name, addr);
861 return;
865 * Each process may define its own FD_SETSIZE, so our fd_set may be of
866 * a different size than theirs. Thus, we copy at a granularity known
867 * to be valid in any case: a single word of bits. We make the
868 * assumption that fd_set consists purely of bits, so that we can use
869 * the second (and so on) bit word as an fd_set by itself.
871 words = (nfds + NFDBITS - 1) / NFDBITS;
873 count = 0;
875 if (verbose == 0)
876 max = 16;
877 else if (verbose == 1)
878 max = FD_SETSIZE;
879 else
880 max = INT_MAX;
882 /* TODO: copy in more at once, but stick to fd_mask boundaries. */
883 for (off = 0, i = 0; i < words; i++, off += sizeof(fd_mask)) {
884 if (mem_get_data(proc->pid, addr + off, &set,
885 sizeof(fd_mask)) != 0) {
886 if (count == 0) {
887 put_ptr(proc, name, addr);
889 return;
892 break;
895 for (j = 0; j < NFDBITS; j++) {
896 if (FD_ISSET(j, &set)) {
897 if (count == 0)
898 put_open(proc, name, PF_NONAME, "[",
899 " ");
901 if (count < max)
902 put_fd(proc, NULL, i * NFDBITS + j);
904 count++;
910 * The empty set should print as "[]". If copying any part failed, it
911 * should print as "[x, ..(?)]" where x is the set printed so far, if
912 * any. If copying never failed, and we did not print all fds in the
913 * set, print the remaining count n as "[x, ..(+n)]" at the end.
915 if (count == 0)
916 put_open(proc, name, PF_NONAME, "[", " ");
918 if (i < words)
919 put_tail(proc, 0, 0);
920 else if (count > max)
921 put_tail(proc, count, max);
923 put_close(proc, "]");
926 static int
927 vfs_select_out(struct trace_proc * proc, const message * m_out)
929 int nfds;
931 nfds = m_out->m_lc_vfs_select.nfds;
933 put_fd(proc, "nfds", nfds); /* not really a file descriptor.. */
934 put_fd_set(proc, "readfds",
935 (vir_bytes)m_out->m_lc_vfs_select.readfds, nfds);
936 put_fd_set(proc, "writefds",
937 (vir_bytes)m_out->m_lc_vfs_select.writefds, nfds);
938 put_fd_set(proc, "errorfds",
939 (vir_bytes)m_out->m_lc_vfs_select.errorfds, nfds);
940 put_struct_timeval(proc, "timeout", 0, m_out->m_lc_vfs_select.timeout);
942 return CT_DONE;
945 static void
946 vfs_select_in(struct trace_proc * proc, const message * m_out,
947 const message * __unused m_in, int failed)
949 vir_bytes readfds, writefds, errorfds;
950 int nfds;
952 put_result(proc);
953 if (failed)
954 return;
956 nfds = m_out->m_lc_vfs_select.nfds;
958 readfds = (vir_bytes)m_out->m_lc_vfs_select.readfds;
959 writefds = (vir_bytes)m_out->m_lc_vfs_select.writefds;
960 errorfds = (vir_bytes)m_out->m_lc_vfs_select.errorfds;
962 if (readfds == 0 && writefds == 0 && errorfds == 0)
963 return;
965 /* Omit names, because it looks weird. */
966 put_open(proc, NULL, PF_NONAME, "(", ", ");
967 if (readfds != 0)
968 put_fd_set(proc, "readfds", readfds, nfds);
969 if (writefds != 0)
970 put_fd_set(proc, "writefds", writefds, nfds);
971 if (errorfds != 0)
972 put_fd_set(proc, "errorfds", errorfds, nfds);
973 put_close(proc, ")");
976 static int
977 vfs_fchdir_out(struct trace_proc * proc, const message * m_out)
980 put_fd(proc, "fd", m_out->m_lc_vfs_fchdir.fd);
982 return CT_DONE;
985 static int
986 vfs_fsync_out(struct trace_proc * proc, const message * m_out)
989 put_fd(proc, "fd", m_out->m_lc_vfs_fsync.fd);
991 return CT_DONE;
994 static int
995 vfs_truncate_out(struct trace_proc * proc, const message * m_out)
998 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_truncate.name,
999 m_out->m_lc_vfs_truncate.len);
1000 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1002 return CT_DONE;
1005 static int
1006 vfs_ftruncate_out(struct trace_proc * proc, const message * m_out)
1009 put_fd(proc, "fd", m_out->m_lc_vfs_truncate.fd);
1010 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1012 return CT_DONE;
1015 static int
1016 vfs_fchmod_out(struct trace_proc * proc, const message * m_out)
1019 put_fd(proc, "fd", m_out->m_lc_vfs_fchmod.fd);
1020 put_mode(proc, "mode", m_out->m_lc_vfs_fchmod.mode);
1022 return CT_DONE;
1025 static int
1026 vfs_fchown_out(struct trace_proc * proc, const message * m_out)
1029 put_fd(proc, "fd", m_out->m_lc_vfs_chown.fd);
1030 /* -1 means "keep the current value" so print as signed */
1031 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner);
1032 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group);
1034 return CT_DONE;
1037 static const char *
1038 vfs_utimens_name(const message * m_out)
1040 int has_path, has_flags;
1042 has_path = (m_out->m_vfs_utimens.name != NULL);
1043 has_flags = (m_out->m_vfs_utimens.flags != 0);
1045 if (has_path && m_out->m_vfs_utimens.flags == AT_SYMLINK_NOFOLLOW)
1046 return "lutimens";
1047 if (has_path && !has_flags)
1048 return "utimens";
1049 else if (!has_path && !has_flags)
1050 return "futimens";
1051 else
1052 return "utimensat";
1055 static const struct flags at_flags[] = {
1056 FLAG(AT_EACCESS),
1057 FLAG(AT_SYMLINK_NOFOLLOW),
1058 FLAG(AT_SYMLINK_FOLLOW),
1059 FLAG(AT_REMOVEDIR),
1062 static void
1063 put_utimens_timespec(struct trace_proc * proc, const char * name,
1064 time_t sec, long nsec)
1067 /* No field names. */
1068 put_open(proc, name, PF_NONAME, "{", ", ");
1070 put_time(proc, "tv_sec", sec);
1072 if (!valuesonly && nsec == UTIME_NOW)
1073 put_field(proc, "tv_nsec", "UTIME_NOW");
1074 else if (!valuesonly && nsec == UTIME_OMIT)
1075 put_field(proc, "tv_nsec", "UTIME_OMIT");
1076 else
1077 put_value(proc, "tv_nsec", "%ld", nsec);
1079 put_close(proc, "}");
1082 static int
1083 vfs_utimens_out(struct trace_proc * proc, const message * m_out)
1085 int has_path, has_flags;
1087 /* Here we do not care about the utimens/lutimens distinction. */
1088 has_path = (m_out->m_vfs_utimens.name != NULL);
1089 has_flags = !!(m_out->m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW);
1091 if (has_path && has_flags)
1092 put_field(proc, "fd", "AT_CWD"); /* utimensat */
1093 else if (!has_path)
1094 put_fd(proc, "fd", m_out->m_vfs_utimens.fd); /* futimes */
1095 if (has_path || has_flags) /* lutimes, utimes, utimensat */
1096 put_buf(proc, "path", PF_PATH,
1097 (vir_bytes)m_out->m_vfs_utimens.name,
1098 m_out->m_vfs_utimens.len);
1100 put_open(proc, "times", 0, "[", ", ");
1101 put_utimens_timespec(proc, "atime", m_out->m_vfs_utimens.atime,
1102 m_out->m_vfs_utimens.ansec);
1103 put_utimens_timespec(proc, "mtime", m_out->m_vfs_utimens.mtime,
1104 m_out->m_vfs_utimens.mnsec);
1105 put_close(proc, "]");
1107 if (has_flags)
1108 put_flags(proc, "flag", at_flags, COUNT(at_flags), "0x%x",
1109 m_out->m_vfs_utimens.flags);
1111 return CT_DONE;
1114 static const struct flags statvfs_flags[] = {
1115 FLAG(ST_WAIT),
1116 FLAG(ST_NOWAIT),
1119 static const struct flags st_flags[] = {
1120 FLAG(ST_RDONLY),
1121 FLAG(ST_SYNCHRONOUS),
1122 FLAG(ST_NOEXEC),
1123 FLAG(ST_NOSUID),
1124 FLAG(ST_NODEV),
1125 FLAG(ST_UNION),
1126 FLAG(ST_ASYNC),
1127 FLAG(ST_NOCOREDUMP),
1128 FLAG(ST_RELATIME),
1129 FLAG(ST_IGNORE),
1130 FLAG(ST_NOATIME),
1131 FLAG(ST_SYMPERM),
1132 FLAG(ST_NODEVMTIME),
1133 FLAG(ST_SOFTDEP),
1134 FLAG(ST_LOG),
1135 FLAG(ST_EXTATTR),
1136 FLAG(ST_EXRDONLY),
1137 FLAG(ST_EXPORTED),
1138 FLAG(ST_DEFEXPORTED),
1139 FLAG(ST_EXPORTANON),
1140 FLAG(ST_EXKERB),
1141 FLAG(ST_EXNORESPORT),
1142 FLAG(ST_EXPUBLIC),
1143 FLAG(ST_LOCAL),
1144 FLAG(ST_QUOTA),
1145 FLAG(ST_ROOTFS),
1146 FLAG(ST_NOTRUNC),
1149 static void
1150 put_struct_statvfs(struct trace_proc * proc, const char * name, int flags,
1151 vir_bytes addr)
1153 struct statvfs buf;
1155 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
1156 return;
1158 put_flags(proc, "f_flag", st_flags, COUNT(st_flags), "0x%x",
1159 buf.f_flag);
1160 put_value(proc, "f_bsize", "%lu", buf.f_bsize);
1161 if (verbose > 0 || buf.f_bsize != buf.f_frsize)
1162 put_value(proc, "f_frsize", "%lu", buf.f_frsize);
1163 if (verbose > 1)
1164 put_value(proc, "f_iosize", "%lu", buf.f_iosize);
1166 put_value(proc, "f_blocks", "%"PRIu64, buf.f_blocks);
1167 put_value(proc, "f_bfree", "%"PRIu64, buf.f_bfree);
1168 if (verbose > 1) {
1169 put_value(proc, "f_bavail", "%"PRIu64, buf.f_bavail);
1170 put_value(proc, "f_bresvd", "%"PRIu64, buf.f_bresvd);
1173 if (verbose > 0) {
1174 put_value(proc, "f_files", "%"PRIu64, buf.f_files);
1175 put_value(proc, "f_ffree", "%"PRIu64, buf.f_ffree);
1177 if (verbose > 1) {
1178 put_value(proc, "f_favail", "%"PRIu64, buf.f_favail);
1179 put_value(proc, "f_fresvd", "%"PRIu64, buf.f_fresvd);
1182 if (verbose > 1) {
1183 put_value(proc, "f_syncreads", "%"PRIu64, buf.f_syncreads);
1184 put_value(proc, "f_syncwrites", "%"PRIu64, buf.f_syncwrites);
1185 put_value(proc, "f_asyncreads", "%"PRIu64, buf.f_asyncreads);
1186 put_value(proc, "f_asyncwrites", "%"PRIu64, buf.f_asyncwrites);
1188 put_value(proc, "f_fsidx", "<%"PRId32",%"PRId32">",
1189 buf.f_fsidx.__fsid_val[0], buf.f_fsidx.__fsid_val[1]);
1191 put_dev(proc, "f_fsid", buf.f_fsid); /* MINIX3 interpretation! */
1193 if (verbose > 0)
1194 put_value(proc, "f_namemax", "%lu", buf.f_namemax);
1195 if (verbose > 1)
1196 put_value(proc, "f_owner", "%u", buf.f_owner);
1198 put_buf(proc, "f_fstypename", PF_STRING | PF_LOCADDR,
1199 (vir_bytes)&buf.f_fstypename, sizeof(buf.f_fstypename));
1200 if (verbose > 0)
1201 put_buf(proc, "f_mntfromname", PF_STRING | PF_LOCADDR,
1202 (vir_bytes)&buf.f_mntfromname, sizeof(buf.f_mntfromname));
1203 put_buf(proc, "f_mntonname", PF_STRING | PF_LOCADDR,
1204 (vir_bytes)&buf.f_mntonname, sizeof(buf.f_mntonname));
1206 put_close_struct(proc, verbose > 1);
1209 static void
1210 put_statvfs_array(struct trace_proc * proc, const char * name, int flags,
1211 vir_bytes addr, int count)
1213 struct statvfs buf;
1214 int i, max;
1216 if ((flags & PF_FAILED) || valuesonly || count < 0) {
1217 put_ptr(proc, name, addr);
1219 return;
1222 if (count == 0) {
1223 put_field(proc, name, "[]");
1225 return;
1228 if (verbose == 0)
1229 max = 0;
1230 else if (verbose == 1)
1231 max = 1; /* TODO: is this reasonable? */
1232 else
1233 max = INT_MAX;
1235 if (max > count)
1236 max = count;
1238 for (i = 0; i < max; i++) {
1239 if (mem_get_data(proc->pid, addr + i * sizeof(buf), &buf,
1240 sizeof(buf)) < 0) {
1241 if (i == 0) {
1242 put_ptr(proc, name, addr);
1244 return;
1247 break;
1250 if (i == 0)
1251 put_open(proc, name, PF_NONAME, "[", ", ");
1253 put_struct_statvfs(proc, NULL, PF_LOCADDR, (vir_bytes)&buf);
1256 if (i == 0)
1257 put_open(proc, name, PF_NONAME, "[", ", ");
1258 if (i < max)
1259 put_tail(proc, 0, 0);
1260 else if (count > i)
1261 put_tail(proc, count, i);
1262 put_close(proc, "]");
1265 static int
1266 vfs_getvfsstat_out(struct trace_proc * proc, const message * m_out)
1269 if (m_out->m_lc_vfs_getvfsstat.buf == 0) {
1270 put_ptr(proc, "buf", m_out->m_lc_vfs_getvfsstat.buf);
1271 put_value(proc, "bufsize", "%zu",
1272 m_out->m_lc_vfs_getvfsstat.len);
1273 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1274 "%d", m_out->m_lc_vfs_getvfsstat.flags);
1275 return CT_DONE;
1276 } else
1277 return CT_NOTDONE;
1280 static void
1281 vfs_getvfsstat_in(struct trace_proc * proc, const message * m_out,
1282 const message * m_in, int failed)
1285 if (m_out->m_lc_vfs_getvfsstat.buf != 0) {
1286 put_statvfs_array(proc, "buf", failed,
1287 m_out->m_lc_vfs_getvfsstat.buf, m_in->m_type);
1288 put_value(proc, "bufsize", "%zu",
1289 m_out->m_lc_vfs_getvfsstat.len);
1290 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1291 "%d", m_out->m_lc_vfs_getvfsstat.flags);
1292 put_equals(proc);
1294 put_result(proc);
1297 static int
1298 vfs_statvfs1_out(struct trace_proc * proc, const message * m_out)
1301 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_statvfs1.name,
1302 m_out->m_lc_vfs_statvfs1.len);
1304 return CT_NOTDONE;
1307 static void
1308 vfs_statvfs1_in(struct trace_proc * proc, const message * m_out,
1309 const message * __unused m_in, int failed)
1312 put_struct_statvfs(proc, "buf", failed, m_out->m_lc_vfs_statvfs1.buf);
1313 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), "%d",
1314 m_out->m_lc_vfs_statvfs1.flags);
1315 put_equals(proc);
1316 put_result(proc);
1319 /* This function is shared between statvfs1 and fstatvfs1. */
1320 static int
1321 vfs_fstatvfs1_out(struct trace_proc * proc, const message * m_out)
1324 put_fd(proc, "fd", m_out->m_lc_vfs_statvfs1.fd);
1326 return CT_NOTDONE;
1329 static int
1330 vfs_svrctl_out(struct trace_proc * proc, const message * m_out)
1333 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request,
1334 TRUE /*is_svrctl*/);
1335 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request,
1336 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1339 static void
1340 vfs_svrctl_in(struct trace_proc * proc, const message * m_out,
1341 const message * __unused m_in, int failed)
1344 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request,
1345 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1348 static int
1349 vfs_gcov_flush_out(struct trace_proc * proc, const message * m_out)
1352 put_ptr(proc, "buff", m_out->m_lc_vfs_gcov.buff_p);
1353 put_value(proc, "buff_sz", "%zu", m_out->m_lc_vfs_gcov.buff_sz);
1354 put_value(proc, "server_pid", "%d", m_out->m_lc_vfs_gcov.pid);
1356 return CT_DONE;
1359 #define VFS_CALL(c) [((VFS_ ## c) - VFS_BASE)]
1361 static const struct call_handler vfs_map[] = {
1362 VFS_CALL(READ) = HANDLER("read", vfs_read_out, vfs_read_in),
1363 VFS_CALL(WRITE) = HANDLER("write", vfs_write_out, default_in),
1364 VFS_CALL(LSEEK) = HANDLER("lseek", vfs_lseek_out, vfs_lseek_in),
1365 VFS_CALL(OPEN) = HANDLER("open", vfs_open_out, vfs_open_in),
1366 VFS_CALL(CREAT) = HANDLER("open", vfs_creat_out, vfs_open_in),
1367 VFS_CALL(CLOSE) = HANDLER("close", vfs_close_out, default_in),
1368 VFS_CALL(LINK) = HANDLER("link", vfs_link_out, default_in),
1369 VFS_CALL(UNLINK) = HANDLER("unlink", vfs_path_out, default_in),
1370 VFS_CALL(CHDIR) = HANDLER("chdir", vfs_path_out, default_in),
1371 VFS_CALL(MKDIR) = HANDLER("mkdir", vfs_path_mode_out, default_in),
1372 VFS_CALL(MKNOD) = HANDLER("mknod", vfs_mknod_out, default_in),
1373 VFS_CALL(CHMOD) = HANDLER("chmod", vfs_path_mode_out, default_in),
1374 VFS_CALL(CHOWN) = HANDLER("chown", vfs_chown_out, default_in),
1375 VFS_CALL(MOUNT) = HANDLER("mount", vfs_mount_out, default_in),
1376 VFS_CALL(UMOUNT) = HANDLER("umount", vfs_umount_out, vfs_umount_in),
1377 VFS_CALL(ACCESS) = HANDLER("access", vfs_access_out, default_in),
1378 VFS_CALL(SYNC) = HANDLER("sync", default_out, default_in),
1379 VFS_CALL(RENAME) = HANDLER("rename", vfs_link_out, default_in),
1380 VFS_CALL(RMDIR) = HANDLER("rmdir", vfs_path_out, default_in),
1381 VFS_CALL(SYMLINK) = HANDLER("symlink", vfs_link_out, default_in),
1382 VFS_CALL(READLINK) = HANDLER("readlink", vfs_readlink_out,
1383 vfs_readlink_in),
1384 VFS_CALL(STAT) = HANDLER("stat", vfs_stat_out, vfs_stat_in),
1385 VFS_CALL(FSTAT) = HANDLER("fstat", vfs_fstat_out, vfs_fstat_in),
1386 VFS_CALL(LSTAT) = HANDLER("lstat", vfs_stat_out, vfs_stat_in),
1387 VFS_CALL(IOCTL) = HANDLER("ioctl", vfs_ioctl_out, vfs_ioctl_in),
1388 VFS_CALL(FCNTL) = HANDLER("fcntl", vfs_fcntl_out, vfs_fcntl_in),
1389 VFS_CALL(PIPE2) = HANDLER("pipe2", vfs_pipe2_out, vfs_pipe2_in),
1390 VFS_CALL(UMASK) = HANDLER("umask", vfs_umask_out, vfs_umask_in),
1391 VFS_CALL(CHROOT) = HANDLER("chroot", vfs_path_out, default_in),
1392 VFS_CALL(GETDENTS) = HANDLER("getdents", vfs_getdents_out,
1393 vfs_getdents_in),
1394 VFS_CALL(SELECT) = HANDLER("select", vfs_select_out, vfs_select_in),
1395 VFS_CALL(FCHDIR) = HANDLER("fchdir", vfs_fchdir_out, default_in),
1396 VFS_CALL(FSYNC) = HANDLER("fsync", vfs_fsync_out, default_in),
1397 VFS_CALL(TRUNCATE) = HANDLER("truncate", vfs_truncate_out, default_in),
1398 VFS_CALL(FTRUNCATE) = HANDLER("ftruncate", vfs_ftruncate_out,
1399 default_in),
1400 VFS_CALL(FCHMOD) = HANDLER("fchmod", vfs_fchmod_out, default_in),
1401 VFS_CALL(FCHOWN) = HANDLER("fchown", vfs_fchown_out, default_in),
1402 VFS_CALL(UTIMENS) = HANDLER_NAME(vfs_utimens_name, vfs_utimens_out,
1403 default_in),
1404 VFS_CALL(GETVFSSTAT) = HANDLER("getvfsstat", vfs_getvfsstat_out,
1405 vfs_getvfsstat_in),
1406 VFS_CALL(STATVFS1) = HANDLER("statvfs1", vfs_statvfs1_out,
1407 vfs_statvfs1_in),
1408 VFS_CALL(FSTATVFS1) = HANDLER("fstatvfs1", vfs_fstatvfs1_out,
1409 vfs_statvfs1_in),
1410 VFS_CALL(SVRCTL) = HANDLER("vfs_svrctl", vfs_svrctl_out,
1411 vfs_svrctl_in),
1412 VFS_CALL(GCOV_FLUSH) = HANDLER("gcov_flush", vfs_gcov_flush_out,
1413 default_in),
1416 const struct calls vfs_calls = {
1417 .endpt = VFS_PROC_NR,
1418 .base = VFS_BASE,
1419 .map = vfs_map,
1420 .count = COUNT(vfs_map)