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).
16 put_fd(struct trace_proc
* proc
, const char * name
, int fd
)
19 put_value(proc
, name
, "%d", fd
);
23 vfs_read_out(struct trace_proc
* proc
, const message
*m_out
)
26 put_fd(proc
, "fd", m_out
->m_lc_vfs_readwrite
.fd
);
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
,
38 put_value(proc
, "len", "%zu", m_out
->m_lc_vfs_readwrite
.len
);
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
);
56 put_lseek_whence(struct trace_proc
* proc
, const char * name
, int whence
)
58 const char *text
= NULL
;
69 put_field(proc
, name
, text
);
71 put_value(proc
, name
, "%d", whence
);
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
);
86 vfs_lseek_in(struct trace_proc
* proc
, const message
* __unused m_out
,
87 const message
* m_in
, int failed
)
91 put_value(proc
, NULL
, "%"PRId64
, m_in
->m_vfs_lc_lseek
.offset
);
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 */
123 put_open_flags(struct trace_proc
* proc
, const char * name
, int value
,
126 const struct flags
*fp
;
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.
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
),
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)
166 put_path(struct trace_proc
* proc
, const message
* m_out
)
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
);
174 put_buf(proc
, "path", PF_PATH
, m_out
->m_lc_vfs_path
.name
, len
);
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
,
188 /* This function is shared between creat and open. */
190 vfs_open_in(struct trace_proc
* proc
, const message
* __unused m_out
,
191 const message
* m_in
, int failed
)
195 put_fd(proc
, NULL
, m_in
->m_type
);
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
,
208 put_mode(proc
, "mode", m_out
->m_lc_vfs_creat
.mode
);
214 vfs_close_out(struct trace_proc
* proc
, const message
* m_out
)
217 put_fd(proc
, "fd", m_out
->m_lc_vfs_close
.fd
);
222 /* This function is used for link, rename, and symlink. */
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
);
236 vfs_path_out(struct trace_proc
* proc
, const message
* m_out
)
239 put_path(proc
, m_out
);
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
);
255 put_dev(struct trace_proc
* proc
, const char * name
, dev_t 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
);
267 put_value(proc
, name
, "%"PRIu64
, dev
);
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
);
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
);
295 /* TODO: expand this to the full ST_ set. */
296 static const struct flags mount_flags
[] = {
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
);
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
);
329 vfs_umount_in(struct trace_proc
* proc
, const message
* m_out
,
330 const message
* __unused m_in
, int 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
[] = {
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
);
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
);
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
,
381 put_value(proc
, "bufsize", "%zd", m_out
->m_lc_vfs_readlink
.bufsize
);
387 put_struct_stat(struct trace_proc
* proc
, const char * name
, int flags
,
393 if (!put_open_struct(proc
, name
, flags
, addr
, &buf
, sizeof(buf
)))
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
));
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
);
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
);
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
);
438 put_value(proc
, "st_blocks", "%"PRId64
, buf
.st_blocks
);
439 put_value(proc
, "st_blksize", "%"PRId32
, buf
.st_blksize
);
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);
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
);
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
);
470 vfs_fstat_out(struct trace_proc
* proc
, const message
* m_out
)
473 put_fd(proc
, "fd", m_out
->m_lc_vfs_fstat
.fd
);
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
);
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*/);
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*/);
509 put_fcntl_cmd(struct trace_proc
* proc
, const char * name
, int cmd
)
511 const char *text
= NULL
;
527 TEXT(F_DUPFD_CLOEXEC
);
528 TEXT(F_GETNOSIGPIPE
);
529 TEXT(F_SETNOSIGPIPE
);
531 TEXT(F_FLUSH_FS_CACHE
);
536 put_field(proc
, name
, text
);
538 put_value(proc
, name
, "%d", cmd
);
541 static const struct flags fd_flags
[] = {
545 #define put_fd_flags(p, n, v) \
546 put_flags(p, n, fd_flags, COUNT(fd_flags), "0x%x", v)
549 put_flock_type(struct trace_proc
* proc
, const char * name
, int type
)
551 const char *text
= NULL
;
562 put_field(proc
, name
, text
);
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.
572 put_struct_flock(struct trace_proc
* proc
, const char * name
, int flags
,
578 if (!put_open_struct(proc
, name
, flags
, addr
, &flock
, sizeof(flock
)))
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
);
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
);
590 put_value(proc
, "l_pid", "%d", flock
.l_pid
);
593 put_close_struct(proc
, TRUE
/*all*/);
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
) {
605 case F_DUPFD_CLOEXEC
:
606 put_fd(proc
, "fd2", m_out
->m_lc_vfs_fcntl
.arg_int
);
609 put_fd_flags(proc
, "flags", m_out
->m_lc_vfs_fcntl
.arg_int
);
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*/);
625 put_struct_flock(proc
, "lkp", 0,
626 m_out
->m_lc_vfs_fcntl
.arg_ptr
);
629 put_struct_flock(proc
, "lkp", PF_ALT
,
630 m_out
->m_lc_vfs_fcntl
.arg_ptr
);
633 put_value(proc
, "arg", "%d", m_out
->m_lc_vfs_fcntl
.arg_int
);
637 return (m_out
->m_lc_vfs_fcntl
.cmd
!= F_GETLK
) ? CT_DONE
: CT_NOTDONE
;
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
) {
649 put_fd_flags(proc
, NULL
, m_in
->m_type
);
654 put_open_flags(proc
, NULL
, m_in
->m_type
, TRUE
/*full*/);
657 put_struct_flock(proc
, "lkp", failed
| PF_FULL
,
658 m_out
->m_lc_vfs_fcntl
.arg_ptr
);
667 vfs_pipe2_out(struct trace_proc
* __unused proc
,
668 const message
* __unused m_out
)
675 vfs_pipe2_in(struct trace_proc
* proc
, const message
* m_out
,
676 const message
* m_in
, int 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
, "]");
685 put_field(proc
, "fd", "&..");
686 put_open_flags(proc
, "flags", m_out
->m_lc_vfs_pipe2
.flags
,
693 vfs_umask_out(struct trace_proc
* proc
, const message
* m_out
)
696 put_mode(proc
, NULL
, m_out
->m_lc_vfs_umask
.mask
);
702 vfs_umask_in(struct trace_proc
* proc
, const message
* __unused m_out
,
703 const message
* m_in
, int failed
)
707 put_mode(proc
, NULL
, m_in
->m_type
);
714 put_dirent_type(struct trace_proc
* proc
, const char * name
, unsigned int type
)
716 const char *text
= NULL
;
733 put_field(proc
, name
, text
);
735 put_value(proc
, name
, "%u", type
);
739 put_struct_dirent(struct trace_proc
* proc
, const char *name
, int flags
,
742 struct dirent dirent
;
744 if (!put_open_struct(proc
, name
, flags
, addr
, &dirent
, sizeof(dirent
)))
748 put_value(proc
, "d_fileno", "%"PRIu64
, dirent
.d_fileno
);
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);
762 put_dirent_array(struct trace_proc
* proc
, const char * name
, int flags
,
763 vir_bytes addr
, ssize_t size
)
765 struct dirent dirent
;
769 if ((flags
& PF_FAILED
) || valuesonly
> 1 || size
< 0) {
770 put_ptr(proc
, name
, addr
);
776 put_field(proc
, name
, "[]");
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 */
789 * TODO: as is, this is highly inefficient, as we are typically copying
790 * in the same pieces of memory in repeatedly..
793 for (off
= 0; off
< size
; off
+= chunk
) {
795 if ((size_t)chunk
> sizeof(dirent
))
796 chunk
= (ssize_t
)sizeof(dirent
);
797 if ((size_t)chunk
< _DIRENT_MINSIZE(&dirent
))
800 if (mem_get_data(proc
->pid
, addr
+ off
, &dirent
, chunk
) < 0) {
802 put_ptr(proc
, name
, addr
);
811 put_open(proc
, name
, PF_NONAME
, "[", ", ");
814 put_struct_dirent(proc
, NULL
, PF_LOCADDR
,
817 if (chunk
> dirent
.d_reclen
)
818 chunk
= dirent
.d_reclen
;
823 put_tail(proc
, 0, 0);
824 else if (count
> max
)
825 put_tail(proc
, count
, max
);
826 put_close(proc
, "]");
830 vfs_getdents_out(struct trace_proc
* proc
, const message
* m_out
)
833 put_fd(proc
, "fd", m_out
->m_lc_vfs_readwrite
.fd
);
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
,
845 put_value(proc
, "len", "%zu", m_out
->m_lc_vfs_readwrite
.len
);
851 put_fd_set(struct trace_proc
* proc
, const char * name
, vir_bytes addr
,
856 unsigned int i
, j
, words
, count
, max
;
858 if (addr
== 0 || nfds
< 0) {
859 put_ptr(proc
, name
, addr
);
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
;
877 else if (verbose
== 1)
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) {
887 put_ptr(proc
, name
, addr
);
895 for (j
= 0; j
< NFDBITS
; j
++) {
896 if (FD_ISSET(j
, &set
)) {
898 put_open(proc
, name
, PF_NONAME
, "[",
902 put_fd(proc
, NULL
, i
* NFDBITS
+ j
);
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.
916 put_open(proc
, name
, PF_NONAME
, "[", " ");
919 put_tail(proc
, 0, 0);
920 else if (count
> max
)
921 put_tail(proc
, count
, max
);
923 put_close(proc
, "]");
927 vfs_select_out(struct trace_proc
* proc
, const message
* m_out
)
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
);
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
;
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)
965 /* Omit names, because it looks weird. */
966 put_open(proc
, NULL
, PF_NONAME
, "(", ", ");
968 put_fd_set(proc
, "readfds", readfds
, nfds
);
970 put_fd_set(proc
, "writefds", writefds
, nfds
);
972 put_fd_set(proc
, "errorfds", errorfds
, nfds
);
973 put_close(proc
, ")");
977 vfs_fchdir_out(struct trace_proc
* proc
, const message
* m_out
)
980 put_fd(proc
, "fd", m_out
->m_lc_vfs_fchdir
.fd
);
986 vfs_fsync_out(struct trace_proc
* proc
, const message
* m_out
)
989 put_fd(proc
, "fd", m_out
->m_lc_vfs_fsync
.fd
);
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
);
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
);
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
);
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
);
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
)
1047 if (has_path
&& !has_flags
)
1049 else if (!has_path
&& !has_flags
)
1055 static const struct flags at_flags
[] = {
1057 FLAG(AT_SYMLINK_NOFOLLOW
),
1058 FLAG(AT_SYMLINK_FOLLOW
),
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");
1077 put_value(proc
, "tv_nsec", "%ld", nsec
);
1079 put_close(proc
, "}");
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 */
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
, "]");
1108 put_flags(proc
, "flag", at_flags
, COUNT(at_flags
), "0x%x",
1109 m_out
->m_vfs_utimens
.flags
);
1114 static const struct flags statvfs_flags
[] = {
1119 static const struct flags st_flags
[] = {
1121 FLAG(ST_SYNCHRONOUS
),
1127 FLAG(ST_NOCOREDUMP
),
1132 FLAG(ST_NODEVMTIME
),
1138 FLAG(ST_DEFEXPORTED
),
1139 FLAG(ST_EXPORTANON
),
1141 FLAG(ST_EXNORESPORT
),
1150 put_struct_statvfs(struct trace_proc
* proc
, const char * name
, int flags
,
1155 if (!put_open_struct(proc
, name
, flags
, addr
, &buf
, sizeof(buf
)))
1158 put_flags(proc
, "f_flag", st_flags
, COUNT(st_flags
), "0x%x",
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
);
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
);
1169 put_value(proc
, "f_bavail", "%"PRIu64
, buf
.f_bavail
);
1170 put_value(proc
, "f_bresvd", "%"PRIu64
, buf
.f_bresvd
);
1174 put_value(proc
, "f_files", "%"PRIu64
, buf
.f_files
);
1175 put_value(proc
, "f_ffree", "%"PRIu64
, buf
.f_ffree
);
1178 put_value(proc
, "f_favail", "%"PRIu64
, buf
.f_favail
);
1179 put_value(proc
, "f_fresvd", "%"PRIu64
, buf
.f_fresvd
);
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! */
1194 put_value(proc
, "f_namemax", "%lu", buf
.f_namemax
);
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
));
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);
1210 put_statvfs_array(struct trace_proc
* proc
, const char * name
, int flags
,
1211 vir_bytes addr
, int count
)
1216 if ((flags
& PF_FAILED
) || valuesonly
|| count
< 0) {
1217 put_ptr(proc
, name
, addr
);
1223 put_field(proc
, name
, "[]");
1230 else if (verbose
== 1)
1231 max
= 1; /* TODO: is this reasonable? */
1238 for (i
= 0; i
< max
; i
++) {
1239 if (mem_get_data(proc
->pid
, addr
+ i
* sizeof(buf
), &buf
,
1242 put_ptr(proc
, name
, addr
);
1251 put_open(proc
, name
, PF_NONAME
, "[", ", ");
1253 put_struct_statvfs(proc
, NULL
, PF_LOCADDR
, (vir_bytes
)&buf
);
1257 put_open(proc
, name
, PF_NONAME
, "[", ", ");
1259 put_tail(proc
, 0, 0);
1261 put_tail(proc
, count
, i
);
1262 put_close(proc
, "]");
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
);
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
);
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
);
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
);
1319 /* This function is shared between statvfs1 and fstatvfs1. */
1321 vfs_fstatvfs1_out(struct trace_proc
* proc
, const message
* m_out
)
1324 put_fd(proc
, "fd", m_out
->m_lc_vfs_statvfs1
.fd
);
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*/);
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*/);
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
);
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
,
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
,
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
,
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
,
1404 VFS_CALL(GETVFSSTAT
) = HANDLER("getvfsstat", vfs_getvfsstat_out
,
1406 VFS_CALL(STATVFS1
) = HANDLER("statvfs1", vfs_statvfs1_out
,
1408 VFS_CALL(FSTATVFS1
) = HANDLER("fstatvfs1", vfs_fstatvfs1_out
,
1410 VFS_CALL(SVRCTL
) = HANDLER("vfs_svrctl", vfs_svrctl_out
,
1412 VFS_CALL(GCOV_FLUSH
) = HANDLER("gcov_flush", vfs_gcov_flush_out
,
1416 const struct calls vfs_calls
= {
1417 .endpt
= VFS_PROC_NR
,
1420 .count
= COUNT(vfs_map
)