Improve the process for GNU tools
[minix3.git] / minix / usr.bin / trace / service / vfs.c
blob938371ed2be29e29683746e31f622116149482cc
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>
9 #include <sys/socket.h>
10 #include <sys/un.h>
11 #include <netinet/in.h>
12 #if 0 /* not yet, header is missing */
13 #include <netbt/bluetooth.h>
14 #endif
15 #include <arpa/inet.h>
18 * This function should always be used when printing a file descriptor. It
19 * currently offers no benefit, but will in the future allow for features such
20 * as color highlighting and tracking of specific open files (TODO).
22 void
23 put_fd(struct trace_proc * proc, const char * name, int fd)
26 put_value(proc, name, "%d", fd);
29 static int
30 vfs_read_out(struct trace_proc * proc, const message * m_out)
33 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
35 return CT_NOTDONE;
38 static void
39 vfs_read_in(struct trace_proc * proc, const message * m_out,
40 const message * m_in, int failed)
43 put_buf(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf,
44 m_in->m_type);
45 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
46 put_equals(proc);
47 put_result(proc);
50 static int
51 vfs_write_out(struct trace_proc * proc, const message * m_out)
54 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
55 put_buf(proc, "buf", 0, m_out->m_lc_vfs_readwrite.buf,
56 m_out->m_lc_vfs_readwrite.len);
57 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
59 return CT_DONE;
62 static void
63 put_lseek_whence(struct trace_proc * proc, const char * name, int whence)
65 const char *text = NULL;
67 if (!valuesonly) {
68 switch (whence) {
69 TEXT(SEEK_SET);
70 TEXT(SEEK_CUR);
71 TEXT(SEEK_END);
75 if (text != NULL)
76 put_field(proc, name, text);
77 else
78 put_value(proc, name, "%d", whence);
81 static int
82 vfs_lseek_out(struct trace_proc * proc, const message * m_out)
85 put_fd(proc, "fd", m_out->m_lc_vfs_lseek.fd);
86 put_value(proc, "offset", "%"PRId64, m_out->m_lc_vfs_lseek.offset);
87 put_lseek_whence(proc, "whence", m_out->m_lc_vfs_lseek.whence);
89 return CT_DONE;
92 static void
93 vfs_lseek_in(struct trace_proc * proc, const message * __unused m_out,
94 const message * m_in, int failed)
97 if (!failed)
98 put_value(proc, NULL, "%"PRId64, m_in->m_vfs_lc_lseek.offset);
99 else
100 put_result(proc);
103 static const struct flags open_flags[] = {
104 FLAG_MASK(O_ACCMODE, O_RDONLY),
105 FLAG_MASK(O_ACCMODE, O_WRONLY),
106 FLAG_MASK(O_ACCMODE, O_RDWR),
107 #define ACCMODE_ENTRIES 3 /* the first N entries are for O_ACCMODE */
108 FLAG(O_NONBLOCK),
109 FLAG(O_APPEND),
110 FLAG(O_SHLOCK),
111 FLAG(O_EXLOCK),
112 FLAG(O_ASYNC),
113 FLAG(O_SYNC),
114 FLAG(O_NOFOLLOW),
115 FLAG(O_CREAT),
116 FLAG(O_TRUNC),
117 FLAG(O_EXCL),
118 FLAG(O_NOCTTY),
119 FLAG(O_DSYNC),
120 FLAG(O_RSYNC),
121 FLAG(O_ALT_IO),
122 FLAG(O_DIRECT),
123 FLAG(O_DIRECTORY),
124 FLAG(O_CLOEXEC),
125 FLAG(O_SEARCH),
126 FLAG(O_NOSIGPIPE),
129 static void
130 put_open_flags(struct trace_proc * proc, const char * name, int value,
131 int full)
133 const struct flags *fp;
134 unsigned int num;
136 fp = open_flags;
137 num = COUNT(open_flags);
140 * If we're not printing a full open()-style set of flags, but instead
141 * just a loose set of flags, then skip the access mode altogether,
142 * otherwise we'd be printing O_RDONLY when no access mode is given.
144 if (!full) {
145 fp += ACCMODE_ENTRIES;
146 num -= ACCMODE_ENTRIES;
149 put_flags(proc, name, fp, num, "0x%x", value);
152 static const struct flags mode_flags[] = {
153 FLAG_MASK(S_IFMT, S_IFIFO),
154 FLAG_MASK(S_IFMT, S_IFCHR),
155 FLAG_MASK(S_IFMT, S_IFDIR),
156 FLAG_MASK(S_IFMT, S_IFBLK),
157 FLAG_MASK(S_IFMT, S_IFREG),
158 FLAG_MASK(S_IFMT, S_IFLNK),
159 FLAG_MASK(S_IFMT, S_IFSOCK),
160 FLAG_MASK(S_IFMT, S_IFWHT),
161 FLAG(S_ARCH1),
162 FLAG(S_ARCH2),
163 FLAG(S_ISUID),
164 FLAG(S_ISGID),
165 FLAG(S_ISTXT),
168 /* Do not use %04o instead of 0%03o; it is octal even if greater than 0777. */
169 #define put_mode(p, n, v) \
170 put_flags(p, n, mode_flags, COUNT(mode_flags), "0%03o", v)
172 static void
173 put_path(struct trace_proc * proc, const message * m_out)
175 size_t len;
177 if ((len = m_out->m_lc_vfs_path.len) <= M_PATH_STRING_MAX)
178 put_buf(proc, "path", PF_LOCADDR | PF_PATH,
179 (vir_bytes)m_out->m_lc_vfs_path.buf, len);
180 else
181 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_path.name, len);
184 static int
185 vfs_open_out(struct trace_proc * proc, const message * m_out)
188 put_path(proc, m_out);
189 put_open_flags(proc, "flags", m_out->m_lc_vfs_path.flags,
190 TRUE /*full*/);
192 return CT_DONE;
195 /* This function is shared between creat and open. */
196 static void
197 vfs_open_in(struct trace_proc * proc, const message * __unused m_out,
198 const message * m_in, int failed)
201 if (!failed)
202 put_fd(proc, NULL, m_in->m_type);
203 else
204 put_result(proc);
207 static int
208 vfs_creat_out(struct trace_proc * proc, const message * m_out)
211 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_creat.name,
212 m_out->m_lc_vfs_creat.len);
213 put_open_flags(proc, "flags", m_out->m_lc_vfs_creat.flags,
214 TRUE /*full*/);
215 put_mode(proc, "mode", m_out->m_lc_vfs_creat.mode);
217 return CT_DONE;
220 static int
221 vfs_close_out(struct trace_proc * proc, const message * m_out)
224 put_fd(proc, "fd", m_out->m_lc_vfs_close.fd);
226 return CT_DONE;
229 /* This function is used for link, rename, and symlink. */
230 static int
231 vfs_link_out(struct trace_proc * proc, const message * m_out)
234 put_buf(proc, "path1", PF_PATH, m_out->m_lc_vfs_link.name1,
235 m_out->m_lc_vfs_link.len1);
236 put_buf(proc, "path2", PF_PATH, m_out->m_lc_vfs_link.name2,
237 m_out->m_lc_vfs_link.len2);
239 return CT_DONE;
242 static int
243 vfs_path_out(struct trace_proc * proc, const message * m_out)
246 put_path(proc, m_out);
248 return CT_DONE;
251 static int
252 vfs_path_mode_out(struct trace_proc * proc, const message * m_out)
255 put_path(proc, m_out);
256 put_mode(proc, "mode", m_out->m_lc_vfs_path.mode);
258 return CT_DONE;
261 void
262 put_dev(struct trace_proc * proc, const char * name, dev_t dev)
264 devmajor_t major;
265 devminor_t minor;
267 major = major(dev);
268 minor = minor(dev);
270 /* The value 0 ("no device") should print as "0". */
271 if (dev != 0 && makedev(major, minor) == dev && !valuesonly)
272 put_value(proc, name, "<%d,%d>", major, minor);
273 else
274 put_value(proc, name, "%"PRIu64, dev);
277 static int
278 vfs_mknod_out(struct trace_proc * proc, const message * m_out)
281 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mknod.name,
282 m_out->m_lc_vfs_mknod.len);
283 put_mode(proc, "mode", m_out->m_lc_vfs_mknod.mode);
284 put_dev(proc, "dev", m_out->m_lc_vfs_mknod.device);
286 return CT_DONE;
289 static int
290 vfs_chown_out(struct trace_proc * proc, const message * m_out)
293 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_chown.name,
294 m_out->m_lc_vfs_chown.len);
295 /* -1 means "keep the current value" so print as signed */
296 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner);
297 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group);
299 return CT_DONE;
302 /* TODO: expand this to the full ST_ set. */
303 static const struct flags mount_flags[] = {
304 FLAG(MNT_RDONLY),
307 static int
308 vfs_mount_out(struct trace_proc * proc, const message * m_out)
311 put_buf(proc, "special", PF_PATH, m_out->m_lc_vfs_mount.dev,
312 m_out->m_lc_vfs_mount.devlen);
313 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_mount.path,
314 m_out->m_lc_vfs_mount.pathlen);
315 put_flags(proc, "flags", mount_flags, COUNT(mount_flags), "0x%x",
316 m_out->m_lc_vfs_mount.flags);
317 put_buf(proc, "type", PF_STRING, m_out->m_lc_vfs_mount.type,
318 m_out->m_lc_vfs_mount.typelen);
319 put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_mount.label,
320 m_out->m_lc_vfs_mount.labellen);
322 return CT_DONE;
325 static int
326 vfs_umount_out(struct trace_proc * proc, const message * m_out)
329 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_umount.name,
330 m_out->m_lc_vfs_umount.namelen);
332 return CT_DONE;
335 static void
336 vfs_umount_in(struct trace_proc * proc, const message * m_out,
337 const message * __unused m_in, int failed)
340 put_result(proc);
342 if (!failed) {
343 put_open(proc, NULL, 0, "(", ", ");
344 put_buf(proc, "label", PF_STRING, m_out->m_lc_vfs_umount.label,
345 m_out->m_lc_vfs_umount.labellen);
347 put_close(proc, ")");
352 static const struct flags access_flags[] = {
353 FLAG_ZERO(F_OK),
354 FLAG(R_OK),
355 FLAG(W_OK),
356 FLAG(X_OK),
359 static int
360 vfs_access_out(struct trace_proc * proc, const message * m_out)
363 put_path(proc, m_out);
364 put_flags(proc, "mode", access_flags, COUNT(access_flags), "0x%x",
365 m_out->m_lc_vfs_path.mode);
367 return CT_DONE;
370 static int
371 vfs_readlink_out(struct trace_proc * proc, const message * m_out)
374 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_readlink.name,
375 m_out->m_lc_vfs_readlink.namelen);
377 return CT_NOTDONE;
380 static void
381 vfs_readlink_in(struct trace_proc * proc, const message * m_out,
382 const message * m_in, int failed)
385 /* The call does not return a string, so do not use PF_STRING here. */
386 put_buf(proc, "buf", failed, m_out->m_lc_vfs_readlink.buf,
387 m_in->m_type);
388 put_value(proc, "bufsize", "%zd", m_out->m_lc_vfs_readlink.bufsize);
389 put_equals(proc);
390 put_result(proc);
393 static void
394 put_struct_stat(struct trace_proc * proc, const char * name, int flags,
395 vir_bytes addr)
397 struct stat buf;
398 int is_special;
400 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
401 return;
404 * The combination of struct stat's frequent usage and large number of
405 * fields makes this structure a pain to print. For now, the idea is
406 * that for verbosity level 0, we print the mode, and the target device
407 * for block/char special files or the file size for all other files.
408 * For higher verbosity levels, largely maintain the structure's own
409 * order of fields. Violate this general structure printing rule for
410 * some fields though, because the actual field order in struct stat is
411 * downright ridiculous. Like elsewhere, for verbosity level 1 print
412 * all fields with meaningful values, and for verbosity level 2 just
413 * print everything, including fields that are known to be not yet
414 * supported and fields that contain known values.
416 is_special = (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
418 if (verbose > 0) {
419 put_dev(proc, "st_dev", buf.st_dev);
420 put_value(proc, "st_ino", "%"PRId64, buf.st_ino);
422 put_mode(proc, "st_mode", buf.st_mode);
423 if (verbose > 0) {
424 put_value(proc, "st_nlink", "%u", buf.st_nlink);
425 put_value(proc, "st_uid", "%u", buf.st_uid);
426 put_value(proc, "st_gid", "%u", buf.st_gid);
428 if (is_special || verbose > 1)
429 put_dev(proc, "st_rdev", buf.st_rdev);
430 if (verbose > 0) {
432 * TODO: print the nanosecond part, but possibly only if we are
433 * not actually interpreting the time as a date (another TODO),
434 * and/or possibly only with verbose > 1 (largely unsupported).
436 put_time(proc, "st_atime", buf.st_atime);
437 put_time(proc, "st_mtime", buf.st_mtime);
438 put_time(proc, "st_ctime", buf.st_ctime);
440 if (verbose > 1) /* not yet supported on MINIX3 */
441 put_time(proc, "st_birthtime", buf.st_birthtime);
442 if (!is_special || verbose > 1)
443 put_value(proc, "st_size", "%"PRId64, buf.st_size);
444 if (verbose > 0) {
445 put_value(proc, "st_blocks", "%"PRId64, buf.st_blocks);
446 put_value(proc, "st_blksize", "%"PRId32, buf.st_blksize);
448 if (verbose > 1) {
449 put_value(proc, "st_flags", "%"PRIu32, buf.st_flags);
450 put_value(proc, "st_gen", "%"PRIu32, buf.st_gen);
453 put_close_struct(proc, verbose > 1);
456 static int
457 vfs_stat_out(struct trace_proc * proc, const message * m_out)
460 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_stat.name,
461 m_out->m_lc_vfs_stat.len);
463 return CT_NOTDONE;
466 static void
467 vfs_stat_in(struct trace_proc * proc, const message * m_out,
468 const message * __unused m_in, int failed)
471 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_stat.buf);
472 put_equals(proc);
473 put_result(proc);
476 static int
477 vfs_fstat_out(struct trace_proc * proc, const message * m_out)
480 put_fd(proc, "fd", m_out->m_lc_vfs_fstat.fd);
482 return CT_NOTDONE;
485 static void
486 vfs_fstat_in(struct trace_proc * proc, const message * m_out,
487 const message * __unused m_in, int failed)
490 put_struct_stat(proc, "buf", failed, m_out->m_lc_vfs_fstat.buf);
491 put_equals(proc);
492 put_result(proc);
495 static int
496 vfs_ioctl_out(struct trace_proc * proc, const message * m_out)
499 put_fd(proc, "fd", m_out->m_lc_vfs_ioctl.fd);
500 put_ioctl_req(proc, "req", m_out->m_lc_vfs_ioctl.req,
501 FALSE /*is_svrctl*/);
502 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_vfs_ioctl.req,
503 (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/);
506 static void
507 vfs_ioctl_in(struct trace_proc * proc, const message * m_out,
508 const message * __unused m_in, int failed)
511 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_vfs_ioctl.req,
512 (vir_bytes)m_out->m_lc_vfs_ioctl.arg, FALSE /*is_svrctl*/);
515 static void
516 put_fcntl_cmd(struct trace_proc * proc, const char * name, int cmd)
518 const char *text = NULL;
520 if (!valuesonly) {
521 switch (cmd) {
522 TEXT(F_DUPFD);
523 TEXT(F_GETFD);
524 TEXT(F_SETFD);
525 TEXT(F_GETFL);
526 TEXT(F_SETFL);
527 TEXT(F_GETOWN);
528 TEXT(F_SETOWN);
529 TEXT(F_GETLK);
530 TEXT(F_SETLK);
531 TEXT(F_SETLKW);
532 TEXT(F_CLOSEM);
533 TEXT(F_MAXFD);
534 TEXT(F_DUPFD_CLOEXEC);
535 TEXT(F_GETNOSIGPIPE);
536 TEXT(F_SETNOSIGPIPE);
537 TEXT(F_FREESP);
538 TEXT(F_FLUSH_FS_CACHE);
542 if (text != NULL)
543 put_field(proc, name, text);
544 else
545 put_value(proc, name, "%d", cmd);
548 static const struct flags fd_flags[] = {
549 FLAG(FD_CLOEXEC),
552 #define put_fd_flags(p, n, v) \
553 put_flags(p, n, fd_flags, COUNT(fd_flags), "0x%x", v)
555 static void
556 put_flock_type(struct trace_proc * proc, const char * name, int type)
558 const char *text = NULL;
560 if (!valuesonly) {
561 switch (type) {
562 TEXT(F_RDLCK);
563 TEXT(F_UNLCK);
564 TEXT(F_WRLCK);
568 if (text != NULL)
569 put_field(proc, name, text);
570 else
571 put_value(proc, name, "%d", type);
575 * With PF_FULL, also print l_pid, unless l_type is F_UNLCK in which case
576 * only that type is printed. With PF_ALT, print only l_whence/l_start/l_len.
578 static void
579 put_struct_flock(struct trace_proc * proc, const char * name, int flags,
580 vir_bytes addr)
582 struct flock flock;
583 int limited;
585 if (!put_open_struct(proc, name, flags, addr, &flock, sizeof(flock)))
586 return;
588 limited = ((flags & PF_FULL) && flock.l_type == F_UNLCK);
590 if (!(flags & PF_ALT))
591 put_flock_type(proc, "l_type", flock.l_type);
592 if (!limited) {
593 put_lseek_whence(proc, "l_whence", flock.l_whence);
594 put_value(proc, "l_start", "%"PRId64, flock.l_start);
595 put_value(proc, "l_len", "%"PRId64, flock.l_len);
596 if (flags & PF_FULL)
597 put_value(proc, "l_pid", "%d", flock.l_pid);
600 put_close_struct(proc, TRUE /*all*/);
603 static int
604 vfs_fcntl_out(struct trace_proc * proc, const message * m_out)
607 put_fd(proc, "fd", m_out->m_lc_vfs_fcntl.fd);
608 put_fcntl_cmd(proc, "cmd", m_out->m_lc_vfs_fcntl.cmd);
610 switch (m_out->m_lc_vfs_fcntl.cmd) {
611 case F_DUPFD:
612 case F_DUPFD_CLOEXEC:
613 put_fd(proc, "fd2", m_out->m_lc_vfs_fcntl.arg_int);
614 break;
615 case F_SETFD:
616 put_fd_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int);
617 break;
618 case F_SETFL:
620 * One of those difficult cases: the access mode is ignored, so
621 * we don't want to print O_RDONLY if it is not given. On the
622 * other hand, fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_..) is
623 * a fairly common construction, in which case we don't want to
624 * print eg O_..|0x2 if the access mode is O_RDWR. Thus, we
625 * compromise: show the access mode if any of its bits are set.
627 put_open_flags(proc, "flags", m_out->m_lc_vfs_fcntl.arg_int,
628 m_out->m_lc_vfs_fcntl.arg_int & O_ACCMODE /*full*/);
629 break;
630 case F_SETLK:
631 case F_SETLKW:
632 put_struct_flock(proc, "lkp", 0,
633 m_out->m_lc_vfs_fcntl.arg_ptr);
634 break;
635 case F_FREESP:
636 put_struct_flock(proc, "lkp", PF_ALT,
637 m_out->m_lc_vfs_fcntl.arg_ptr);
638 break;
639 case F_SETNOSIGPIPE:
640 put_value(proc, "arg", "%d", m_out->m_lc_vfs_fcntl.arg_int);
641 break;
644 return (m_out->m_lc_vfs_fcntl.cmd != F_GETLK) ? CT_DONE : CT_NOTDONE;
647 static void
648 vfs_fcntl_in(struct trace_proc * proc, const message * m_out,
649 const message * m_in, int failed)
652 switch (m_out->m_lc_vfs_fcntl.cmd) {
653 case F_GETFD:
654 if (failed)
655 break;
656 put_fd_flags(proc, NULL, m_in->m_type);
657 return;
658 case F_GETFL:
659 if (failed)
660 break;
661 put_open_flags(proc, NULL, m_in->m_type, TRUE /*full*/);
662 return;
663 case F_GETLK:
664 put_struct_flock(proc, "lkp", failed | PF_FULL,
665 m_out->m_lc_vfs_fcntl.arg_ptr);
666 put_equals(proc);
667 break;
670 put_result(proc);
673 static int
674 vfs_pipe2_out(struct trace_proc * __unused proc,
675 const message * __unused m_out)
678 return CT_NOTDONE;
681 static void
682 vfs_pipe2_in(struct trace_proc * proc, const message * m_out,
683 const message * m_in, int failed)
686 if (!failed) {
687 put_open(proc, "fd", PF_NONAME, "[", ", ");
688 put_fd(proc, "rfd", m_in->m_vfs_lc_fdpair.fd0);
689 put_fd(proc, "wfd", m_in->m_vfs_lc_fdpair.fd1);
690 put_close(proc, "]");
691 } else
692 put_field(proc, "fd", "&..");
693 put_open_flags(proc, "flags", m_out->m_lc_vfs_pipe2.flags,
694 FALSE /*full*/);
695 put_equals(proc);
696 put_result(proc);
699 static int
700 vfs_umask_out(struct trace_proc * proc, const message * m_out)
703 put_mode(proc, NULL, m_out->m_lc_vfs_umask.mask);
705 return CT_DONE;
708 static void
709 vfs_umask_in(struct trace_proc * proc, const message * __unused m_out,
710 const message * m_in, int failed)
713 if (!failed)
714 put_mode(proc, NULL, m_in->m_type);
715 else
716 put_result(proc);
720 static void
721 put_dirent_type(struct trace_proc * proc, const char * name, unsigned int type)
723 const char *text = NULL;
725 if (!valuesonly) {
726 switch (type) {
727 TEXT(DT_UNKNOWN);
728 TEXT(DT_FIFO);
729 TEXT(DT_CHR);
730 TEXT(DT_DIR);
731 TEXT(DT_BLK);
732 TEXT(DT_REG);
733 TEXT(DT_LNK);
734 TEXT(DT_SOCK);
735 TEXT(DT_WHT);
739 if (text != NULL)
740 put_field(proc, name, text);
741 else
742 put_value(proc, name, "%u", type);
745 static void
746 put_struct_dirent(struct trace_proc * proc, const char *name, int flags,
747 vir_bytes addr)
749 struct dirent dirent;
751 if (!put_open_struct(proc, name, flags, addr, &dirent, sizeof(dirent)))
752 return;
754 if (verbose > 0)
755 put_value(proc, "d_fileno", "%"PRIu64, dirent.d_fileno);
756 if (verbose > 1) {
757 put_value(proc, "d_reclen", "%u", dirent.d_reclen);
758 put_value(proc, "d_namlen", "%u", dirent.d_namlen);
760 if (verbose >= 1 + (dirent.d_type == DT_UNKNOWN))
761 put_dirent_type(proc, "d_type", dirent.d_type);
762 put_buf(proc, "d_name", PF_LOCADDR, (vir_bytes)dirent.d_name,
763 MIN(dirent.d_namlen, sizeof(dirent.d_name)));
765 put_close_struct(proc, verbose > 1);
768 static void
769 put_dirent_array(struct trace_proc * proc, const char * name, int flags,
770 vir_bytes addr, ssize_t size)
772 struct dirent dirent;
773 unsigned count, max;
774 ssize_t off, chunk;
776 if ((flags & PF_FAILED) || valuesonly > 1 || size < 0) {
777 put_ptr(proc, name, addr);
779 return;
782 if (size == 0) {
783 put_field(proc, name, "[]");
785 return;
788 if (verbose == 0)
789 max = 0; /* TODO: should we set this to 1 instead? */
790 else if (verbose == 1)
791 max = 3; /* low; just to give an indication where we are */
792 else
793 max = INT_MAX;
796 * TODO: as is, this is highly inefficient, as we are typically copying
797 * in the same pieces of memory in repeatedly..
799 count = 0;
800 for (off = 0; off < size; off += chunk) {
801 chunk = size - off;
802 if ((size_t)chunk > sizeof(dirent))
803 chunk = (ssize_t)sizeof(dirent);
804 if ((size_t)chunk < _DIRENT_MINSIZE(&dirent))
805 break;
807 if (mem_get_data(proc->pid, addr + off, &dirent, chunk) < 0) {
808 if (off == 0) {
809 put_ptr(proc, name, addr);
811 return;
814 break;
817 if (off == 0)
818 put_open(proc, name, PF_NONAME, "[", ", ");
820 if (count < max)
821 put_struct_dirent(proc, NULL, PF_LOCADDR,
822 (vir_bytes)&dirent);
824 if (chunk > dirent.d_reclen)
825 chunk = dirent.d_reclen;
826 count++;
829 if (off < size)
830 put_tail(proc, 0, 0);
831 else if (count > max)
832 put_tail(proc, count, max);
833 put_close(proc, "]");
836 static int
837 vfs_getdents_out(struct trace_proc * proc, const message * m_out)
840 put_fd(proc, "fd", m_out->m_lc_vfs_readwrite.fd);
842 return CT_NOTDONE;
845 static void
846 vfs_getdents_in(struct trace_proc * proc, const message * m_out,
847 const message * m_in, int failed)
850 put_dirent_array(proc, "buf", failed, m_out->m_lc_vfs_readwrite.buf,
851 m_in->m_type);
852 put_value(proc, "len", "%zu", m_out->m_lc_vfs_readwrite.len);
853 put_equals(proc);
854 put_result(proc);
857 static void
858 put_fd_set(struct trace_proc * proc, const char * name, vir_bytes addr,
859 int nfds)
861 fd_set set;
862 size_t off;
863 unsigned int i, j, words, count, max;
865 if (addr == 0 || nfds < 0) {
866 put_ptr(proc, name, addr);
868 return;
872 * Each process may define its own FD_SETSIZE, so our fd_set may be of
873 * a different size than theirs. Thus, we copy at a granularity known
874 * to be valid in any case: a single word of bits. We make the
875 * assumption that fd_set consists purely of bits, so that we can use
876 * the second (and so on) bit word as an fd_set by itself.
878 words = (nfds + NFDBITS - 1) / NFDBITS;
880 count = 0;
882 if (verbose == 0)
883 max = 16;
884 else if (verbose == 1)
885 max = FD_SETSIZE;
886 else
887 max = INT_MAX;
889 /* TODO: copy in more at once, but stick to fd_mask boundaries. */
890 for (off = 0, i = 0; i < words; i++, off += sizeof(fd_mask)) {
891 if (mem_get_data(proc->pid, addr + off, &set,
892 sizeof(fd_mask)) != 0) {
893 if (count == 0) {
894 put_ptr(proc, name, addr);
896 return;
899 break;
902 for (j = 0; j < NFDBITS; j++) {
903 if (FD_ISSET(j, &set)) {
904 if (count == 0)
905 put_open(proc, name, PF_NONAME, "[",
906 " ");
908 if (count < max)
909 put_fd(proc, NULL, i * NFDBITS + j);
911 count++;
917 * The empty set should print as "[]". If copying any part failed, it
918 * should print as "[x, ..(?)]" where x is the set printed so far, if
919 * any. If copying never failed, and we did not print all fds in the
920 * set, print the remaining count n as "[x, ..(+n)]" at the end.
922 if (count == 0)
923 put_open(proc, name, PF_NONAME, "[", " ");
925 if (i < words)
926 put_tail(proc, 0, 0);
927 else if (count > max)
928 put_tail(proc, count, max);
930 put_close(proc, "]");
933 static int
934 vfs_select_out(struct trace_proc * proc, const message * m_out)
936 int nfds;
938 nfds = m_out->m_lc_vfs_select.nfds;
940 put_fd(proc, "nfds", nfds); /* not really a file descriptor.. */
941 put_fd_set(proc, "readfds",
942 (vir_bytes)m_out->m_lc_vfs_select.readfds, nfds);
943 put_fd_set(proc, "writefds",
944 (vir_bytes)m_out->m_lc_vfs_select.writefds, nfds);
945 put_fd_set(proc, "errorfds",
946 (vir_bytes)m_out->m_lc_vfs_select.errorfds, nfds);
947 put_struct_timeval(proc, "timeout", 0, m_out->m_lc_vfs_select.timeout);
949 return CT_DONE;
952 static void
953 vfs_select_in(struct trace_proc * proc, const message * m_out,
954 const message * __unused m_in, int failed)
956 vir_bytes readfds, writefds, errorfds;
957 int nfds;
959 put_result(proc);
960 if (failed)
961 return;
963 nfds = m_out->m_lc_vfs_select.nfds;
965 readfds = (vir_bytes)m_out->m_lc_vfs_select.readfds;
966 writefds = (vir_bytes)m_out->m_lc_vfs_select.writefds;
967 errorfds = (vir_bytes)m_out->m_lc_vfs_select.errorfds;
969 if (readfds == 0 && writefds == 0 && errorfds == 0)
970 return;
972 /* Omit names, because it looks weird. */
973 put_open(proc, NULL, PF_NONAME, "(", ", ");
974 if (readfds != 0)
975 put_fd_set(proc, "readfds", readfds, nfds);
976 if (writefds != 0)
977 put_fd_set(proc, "writefds", writefds, nfds);
978 if (errorfds != 0)
979 put_fd_set(proc, "errorfds", errorfds, nfds);
980 put_close(proc, ")");
983 static int
984 vfs_fchdir_out(struct trace_proc * proc, const message * m_out)
987 put_fd(proc, "fd", m_out->m_lc_vfs_fchdir.fd);
989 return CT_DONE;
992 static int
993 vfs_fsync_out(struct trace_proc * proc, const message * m_out)
996 put_fd(proc, "fd", m_out->m_lc_vfs_fsync.fd);
998 return CT_DONE;
1001 static int
1002 vfs_truncate_out(struct trace_proc * proc, const message * m_out)
1005 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_truncate.name,
1006 m_out->m_lc_vfs_truncate.len);
1007 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1009 return CT_DONE;
1012 static int
1013 vfs_ftruncate_out(struct trace_proc * proc, const message * m_out)
1016 put_fd(proc, "fd", m_out->m_lc_vfs_truncate.fd);
1017 put_value(proc, "length", "%"PRId64, m_out->m_lc_vfs_truncate.offset);
1019 return CT_DONE;
1022 static int
1023 vfs_fchmod_out(struct trace_proc * proc, const message * m_out)
1026 put_fd(proc, "fd", m_out->m_lc_vfs_fchmod.fd);
1027 put_mode(proc, "mode", m_out->m_lc_vfs_fchmod.mode);
1029 return CT_DONE;
1032 static int
1033 vfs_fchown_out(struct trace_proc * proc, const message * m_out)
1036 put_fd(proc, "fd", m_out->m_lc_vfs_chown.fd);
1037 /* -1 means "keep the current value" so print as signed */
1038 put_value(proc, "owner", "%d", m_out->m_lc_vfs_chown.owner);
1039 put_value(proc, "group", "%d", m_out->m_lc_vfs_chown.group);
1041 return CT_DONE;
1044 static const char *
1045 vfs_utimens_name(const message * m_out)
1047 int has_path, has_flags;
1049 has_path = (m_out->m_vfs_utimens.name != NULL);
1050 has_flags = (m_out->m_vfs_utimens.flags != 0);
1052 if (has_path && m_out->m_vfs_utimens.flags == AT_SYMLINK_NOFOLLOW)
1053 return "lutimens";
1054 if (has_path && !has_flags)
1055 return "utimens";
1056 else if (!has_path && !has_flags)
1057 return "futimens";
1058 else
1059 return "utimensat";
1062 static const struct flags at_flags[] = {
1063 FLAG(AT_EACCESS),
1064 FLAG(AT_SYMLINK_NOFOLLOW),
1065 FLAG(AT_SYMLINK_FOLLOW),
1066 FLAG(AT_REMOVEDIR),
1069 static void
1070 put_utimens_timespec(struct trace_proc * proc, const char * name,
1071 time_t sec, long nsec)
1074 /* No field names. */
1075 put_open(proc, name, PF_NONAME, "{", ", ");
1077 put_time(proc, "tv_sec", sec);
1079 if (!valuesonly && nsec == UTIME_NOW)
1080 put_field(proc, "tv_nsec", "UTIME_NOW");
1081 else if (!valuesonly && nsec == UTIME_OMIT)
1082 put_field(proc, "tv_nsec", "UTIME_OMIT");
1083 else
1084 put_value(proc, "tv_nsec", "%ld", nsec);
1086 put_close(proc, "}");
1089 static int
1090 vfs_utimens_out(struct trace_proc * proc, const message * m_out)
1092 int has_path, has_flags;
1094 /* Here we do not care about the utimens/lutimens distinction. */
1095 has_path = (m_out->m_vfs_utimens.name != NULL);
1096 has_flags = !!(m_out->m_vfs_utimens.flags & ~AT_SYMLINK_NOFOLLOW);
1098 if (has_path && has_flags)
1099 put_field(proc, "fd", "AT_CWD"); /* utimensat */
1100 else if (!has_path)
1101 put_fd(proc, "fd", m_out->m_vfs_utimens.fd); /* futimes */
1102 if (has_path || has_flags) /* lutimes, utimes, utimensat */
1103 put_buf(proc, "path", PF_PATH,
1104 (vir_bytes)m_out->m_vfs_utimens.name,
1105 m_out->m_vfs_utimens.len);
1107 put_open(proc, "times", 0, "[", ", ");
1108 put_utimens_timespec(proc, "atime", m_out->m_vfs_utimens.atime,
1109 m_out->m_vfs_utimens.ansec);
1110 put_utimens_timespec(proc, "mtime", m_out->m_vfs_utimens.mtime,
1111 m_out->m_vfs_utimens.mnsec);
1112 put_close(proc, "]");
1114 if (has_flags)
1115 put_flags(proc, "flag", at_flags, COUNT(at_flags), "0x%x",
1116 m_out->m_vfs_utimens.flags);
1118 return CT_DONE;
1121 static const struct flags statvfs_flags[] = {
1122 FLAG(ST_WAIT),
1123 FLAG(ST_NOWAIT),
1126 static const struct flags st_flags[] = {
1127 FLAG(ST_RDONLY),
1128 FLAG(ST_SYNCHRONOUS),
1129 FLAG(ST_NOEXEC),
1130 FLAG(ST_NOSUID),
1131 FLAG(ST_NODEV),
1132 FLAG(ST_UNION),
1133 FLAG(ST_ASYNC),
1134 FLAG(ST_NOCOREDUMP),
1135 FLAG(ST_RELATIME),
1136 FLAG(ST_IGNORE),
1137 FLAG(ST_NOATIME),
1138 FLAG(ST_SYMPERM),
1139 FLAG(ST_NODEVMTIME),
1140 FLAG(ST_SOFTDEP),
1141 FLAG(ST_LOG),
1142 FLAG(ST_EXTATTR),
1143 FLAG(ST_EXRDONLY),
1144 FLAG(ST_EXPORTED),
1145 FLAG(ST_DEFEXPORTED),
1146 FLAG(ST_EXPORTANON),
1147 FLAG(ST_EXKERB),
1148 FLAG(ST_EXNORESPORT),
1149 FLAG(ST_EXPUBLIC),
1150 FLAG(ST_LOCAL),
1151 FLAG(ST_QUOTA),
1152 FLAG(ST_ROOTFS),
1153 FLAG(ST_NOTRUNC),
1156 static void
1157 put_struct_statvfs(struct trace_proc * proc, const char * name, int flags,
1158 vir_bytes addr)
1160 struct statvfs buf;
1162 if (!put_open_struct(proc, name, flags, addr, &buf, sizeof(buf)))
1163 return;
1165 put_flags(proc, "f_flag", st_flags, COUNT(st_flags), "0x%x",
1166 buf.f_flag);
1167 put_value(proc, "f_bsize", "%lu", buf.f_bsize);
1168 if (verbose > 0 || buf.f_bsize != buf.f_frsize)
1169 put_value(proc, "f_frsize", "%lu", buf.f_frsize);
1170 if (verbose > 1)
1171 put_value(proc, "f_iosize", "%lu", buf.f_iosize);
1173 put_value(proc, "f_blocks", "%"PRIu64, buf.f_blocks);
1174 put_value(proc, "f_bfree", "%"PRIu64, buf.f_bfree);
1175 if (verbose > 1) {
1176 put_value(proc, "f_bavail", "%"PRIu64, buf.f_bavail);
1177 put_value(proc, "f_bresvd", "%"PRIu64, buf.f_bresvd);
1180 if (verbose > 0) {
1181 put_value(proc, "f_files", "%"PRIu64, buf.f_files);
1182 put_value(proc, "f_ffree", "%"PRIu64, buf.f_ffree);
1184 if (verbose > 1) {
1185 put_value(proc, "f_favail", "%"PRIu64, buf.f_favail);
1186 put_value(proc, "f_fresvd", "%"PRIu64, buf.f_fresvd);
1189 if (verbose > 1) {
1190 put_value(proc, "f_syncreads", "%"PRIu64, buf.f_syncreads);
1191 put_value(proc, "f_syncwrites", "%"PRIu64, buf.f_syncwrites);
1192 put_value(proc, "f_asyncreads", "%"PRIu64, buf.f_asyncreads);
1193 put_value(proc, "f_asyncwrites", "%"PRIu64, buf.f_asyncwrites);
1195 put_value(proc, "f_fsidx", "<%"PRId32",%"PRId32">",
1196 buf.f_fsidx.__fsid_val[0], buf.f_fsidx.__fsid_val[1]);
1198 put_dev(proc, "f_fsid", buf.f_fsid); /* MINIX3 interpretation! */
1200 if (verbose > 0)
1201 put_value(proc, "f_namemax", "%lu", buf.f_namemax);
1202 if (verbose > 1)
1203 put_value(proc, "f_owner", "%u", buf.f_owner);
1205 put_buf(proc, "f_fstypename", PF_STRING | PF_LOCADDR,
1206 (vir_bytes)&buf.f_fstypename, sizeof(buf.f_fstypename));
1207 if (verbose > 0)
1208 put_buf(proc, "f_mntfromname", PF_STRING | PF_LOCADDR,
1209 (vir_bytes)&buf.f_mntfromname, sizeof(buf.f_mntfromname));
1210 put_buf(proc, "f_mntonname", PF_STRING | PF_LOCADDR,
1211 (vir_bytes)&buf.f_mntonname, sizeof(buf.f_mntonname));
1213 put_close_struct(proc, verbose > 1);
1216 static void
1217 put_statvfs_array(struct trace_proc * proc, const char * name, int flags,
1218 vir_bytes addr, int count)
1220 struct statvfs buf;
1221 int i, max;
1223 if ((flags & PF_FAILED) || valuesonly > 1 || count < 0) {
1224 put_ptr(proc, name, addr);
1226 return;
1229 if (count == 0) {
1230 put_field(proc, name, "[]");
1232 return;
1235 if (verbose == 0)
1236 max = 0;
1237 else if (verbose == 1)
1238 max = 1; /* TODO: is this reasonable? */
1239 else
1240 max = INT_MAX;
1242 if (max > count)
1243 max = count;
1245 for (i = 0; i < max; i++) {
1246 if (mem_get_data(proc->pid, addr + i * sizeof(buf), &buf,
1247 sizeof(buf)) < 0) {
1248 if (i == 0) {
1249 put_ptr(proc, name, addr);
1251 return;
1254 break;
1257 if (i == 0)
1258 put_open(proc, name, PF_NONAME, "[", ", ");
1260 put_struct_statvfs(proc, NULL, PF_LOCADDR, (vir_bytes)&buf);
1263 if (i == 0)
1264 put_open(proc, name, PF_NONAME, "[", ", ");
1265 if (i < max)
1266 put_tail(proc, 0, 0);
1267 else if (count > i)
1268 put_tail(proc, count, i);
1269 put_close(proc, "]");
1272 static int
1273 vfs_getvfsstat_out(struct trace_proc * proc, const message * m_out)
1276 if (m_out->m_lc_vfs_getvfsstat.buf == 0) {
1277 put_ptr(proc, "buf", m_out->m_lc_vfs_getvfsstat.buf);
1278 put_value(proc, "bufsize", "%zu",
1279 m_out->m_lc_vfs_getvfsstat.len);
1280 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1281 "%d", m_out->m_lc_vfs_getvfsstat.flags);
1282 return CT_DONE;
1283 } else
1284 return CT_NOTDONE;
1287 static void
1288 vfs_getvfsstat_in(struct trace_proc * proc, const message * m_out,
1289 const message * m_in, int failed)
1292 if (m_out->m_lc_vfs_getvfsstat.buf != 0) {
1293 put_statvfs_array(proc, "buf", failed,
1294 m_out->m_lc_vfs_getvfsstat.buf, m_in->m_type);
1295 put_value(proc, "bufsize", "%zu",
1296 m_out->m_lc_vfs_getvfsstat.len);
1297 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags),
1298 "%d", m_out->m_lc_vfs_getvfsstat.flags);
1299 put_equals(proc);
1301 put_result(proc);
1304 static int
1305 vfs_statvfs1_out(struct trace_proc * proc, const message * m_out)
1308 put_buf(proc, "path", PF_PATH, m_out->m_lc_vfs_statvfs1.name,
1309 m_out->m_lc_vfs_statvfs1.len);
1311 return CT_NOTDONE;
1314 static void
1315 vfs_statvfs1_in(struct trace_proc * proc, const message * m_out,
1316 const message * __unused m_in, int failed)
1319 put_struct_statvfs(proc, "buf", failed, m_out->m_lc_vfs_statvfs1.buf);
1320 put_flags(proc, "flags", statvfs_flags, COUNT(statvfs_flags), "%d",
1321 m_out->m_lc_vfs_statvfs1.flags);
1322 put_equals(proc);
1323 put_result(proc);
1326 /* This function is shared between statvfs1 and fstatvfs1. */
1327 static int
1328 vfs_fstatvfs1_out(struct trace_proc * proc, const message * m_out)
1331 put_fd(proc, "fd", m_out->m_lc_vfs_statvfs1.fd);
1333 return CT_NOTDONE;
1336 static int
1337 vfs_svrctl_out(struct trace_proc * proc, const message * m_out)
1340 put_ioctl_req(proc, "request", m_out->m_lc_svrctl.request,
1341 TRUE /*is_svrctl*/);
1342 return put_ioctl_arg_out(proc, "arg", m_out->m_lc_svrctl.request,
1343 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1346 static void
1347 vfs_svrctl_in(struct trace_proc * proc, const message * m_out,
1348 const message * __unused m_in, int failed)
1351 put_ioctl_arg_in(proc, "arg", failed, m_out->m_lc_svrctl.request,
1352 m_out->m_lc_svrctl.arg, TRUE /*is_svrctl*/);
1355 static int
1356 vfs_gcov_flush_out(struct trace_proc * proc, const message * m_out)
1359 put_ptr(proc, "buff", m_out->m_lc_vfs_gcov.buff_p);
1360 put_value(proc, "buff_sz", "%zu", m_out->m_lc_vfs_gcov.buff_sz);
1361 put_value(proc, "server_pid", "%d", m_out->m_lc_vfs_gcov.pid);
1363 return CT_DONE;
1366 void
1367 put_socket_family(struct trace_proc * proc, const char * name, int family)
1369 const char *text = NULL;
1371 if (!valuesonly) {
1373 * For socket(2) and socketpair(2) this should really be using
1374 * the prefix "PF_" since those functions take a protocol
1375 * family rather than an address family. This rule is applied
1376 * fairly consistently within the system. Here I caved because
1377 * I don't want to duplicate this entire function just for the
1378 * one letter. There are exceptions however; some names only
1379 * exist as "PF_".
1381 switch (family) {
1382 TEXT(AF_UNSPEC);
1383 TEXT(AF_LOCAL);
1384 TEXT(AF_INET);
1385 TEXT(AF_IMPLINK);
1386 TEXT(AF_PUP);
1387 TEXT(AF_CHAOS);
1388 TEXT(AF_NS);
1389 TEXT(AF_ISO);
1390 TEXT(AF_ECMA);
1391 TEXT(AF_DATAKIT);
1392 TEXT(AF_CCITT);
1393 TEXT(AF_SNA);
1394 TEXT(AF_DECnet);
1395 TEXT(AF_DLI);
1396 TEXT(AF_LAT);
1397 TEXT(AF_HYLINK);
1398 TEXT(AF_APPLETALK);
1399 TEXT(AF_OROUTE);
1400 TEXT(AF_LINK);
1401 TEXT(PF_XTP);
1402 TEXT(AF_COIP);
1403 TEXT(AF_CNT);
1404 TEXT(PF_RTIP);
1405 TEXT(AF_IPX);
1406 TEXT(AF_INET6);
1407 TEXT(PF_PIP);
1408 TEXT(AF_ISDN);
1409 TEXT(AF_NATM);
1410 TEXT(AF_ARP);
1411 TEXT(PF_KEY);
1412 TEXT(AF_BLUETOOTH);
1413 TEXT(AF_IEEE80211);
1414 TEXT(AF_MPLS);
1415 TEXT(AF_ROUTE);
1419 if (text != NULL)
1420 put_field(proc, name, text);
1421 else
1422 put_value(proc, name, "%d", family);
1425 static const struct flags socket_types[] = {
1426 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_STREAM),
1427 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_DGRAM),
1428 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_RAW),
1429 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_RDM),
1430 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_SEQPACKET),
1431 FLAG_MASK(~SOCK_FLAGS_MASK, SOCK_CONN_DGRAM),
1432 FLAG(SOCK_CLOEXEC),
1433 FLAG(SOCK_NONBLOCK),
1434 FLAG(SOCK_NOSIGPIPE),
1437 void
1438 put_socket_type(struct trace_proc * proc, const char * name, int type)
1441 put_flags(proc, name, socket_types, COUNT(socket_types), "%d", type);
1444 static void
1445 put_socket_protocol(struct trace_proc * proc, const char * name, int family,
1446 int type, int protocol)
1448 const char *text = NULL;
1450 if (!valuesonly && (type == SOCK_RAW || protocol != 0)) {
1451 switch (family) {
1452 case PF_INET:
1453 case PF_INET6:
1454 /* TODO: is this all that is used in socket(2)? */
1455 switch (protocol) {
1456 TEXT(IPPROTO_IP);
1457 TEXT(IPPROTO_ICMP);
1458 TEXT(IPPROTO_IGMP);
1459 TEXT(IPPROTO_TCP);
1460 TEXT(IPPROTO_UDP);
1461 TEXT(IPPROTO_ICMPV6);
1462 TEXT(IPPROTO_RAW);
1464 break;
1465 #if 0 /* not yet */
1466 case PF_BLUETOOTH:
1467 switch (protocol) {
1468 TEXT(BTPROTO_HCI);
1469 TEXT(BTPROTO_L2CAP);
1470 TEXT(BTPROTO_RFCOMM);
1471 TEXT(BTPROTO_SCO);
1473 break;
1474 #endif
1478 if (text != NULL)
1479 put_field(proc, name, text);
1480 else
1481 put_value(proc, name, "%d", protocol);
1484 static int
1485 vfs_socket_out(struct trace_proc * proc, const message * m_out)
1488 put_socket_family(proc, "domain", m_out->m_lc_vfs_socket.domain);
1489 put_socket_type(proc, "type", m_out->m_lc_vfs_socket.type);
1490 put_socket_protocol(proc, "protocol", m_out->m_lc_vfs_socket.domain,
1491 m_out->m_lc_vfs_socket.type & ~SOCK_FLAGS_MASK,
1492 m_out->m_lc_vfs_socket.protocol);
1494 return CT_DONE;
1497 static int
1498 vfs_socketpair_out(struct trace_proc * proc, const message * m_out)
1501 put_socket_family(proc, "domain", m_out->m_lc_vfs_socket.domain);
1502 put_socket_type(proc, "type", m_out->m_lc_vfs_socket.type);
1503 put_socket_protocol(proc, "protocol", m_out->m_lc_vfs_socket.domain,
1504 m_out->m_lc_vfs_socket.type & ~SOCK_FLAGS_MASK,
1505 m_out->m_lc_vfs_socket.protocol);
1507 return CT_NOTDONE;
1510 static void
1511 vfs_socketpair_in(struct trace_proc * proc, const message * m_out,
1512 const message * m_in, int failed)
1515 if (!failed) {
1516 put_open(proc, "fd", PF_NONAME, "[", ", ");
1517 put_fd(proc, "fd0", m_in->m_vfs_lc_fdpair.fd0);
1518 put_fd(proc, "fd1", m_in->m_vfs_lc_fdpair.fd1);
1519 put_close(proc, "]");
1520 } else
1521 put_field(proc, "fd", "&..");
1522 put_equals(proc);
1523 put_result(proc);
1526 void
1527 put_in_addr(struct trace_proc * proc, const char * name, struct in_addr in)
1530 if (!valuesonly) {
1531 /* Is this an acceptable encapsulation? */
1532 put_value(proc, name, "[%s]", inet_ntoa(in));
1533 } else
1534 put_value(proc, name, "0x%08x", ntohl(in.s_addr));
1537 static void
1538 put_in6_addr(struct trace_proc * proc, const char * name, struct in6_addr * in)
1540 char buf[INET6_ADDRSTRLEN];
1541 const char *ptr;
1542 unsigned int i, n;
1544 if (!valuesonly &&
1545 (ptr = inet_ntop(AF_INET6, in, buf, sizeof(buf))) != NULL) {
1546 put_value(proc, name, "[%s]", ptr);
1547 } else {
1548 for (i = n = 0; i < 16; i++)
1549 n += snprintf(buf + n, sizeof(buf) - n, "%02x",
1550 ((unsigned char *)in)[i]);
1551 put_value(proc, name, "0x%s", buf);
1555 static void
1556 put_struct_sockaddr(struct trace_proc * proc, const char * name, int flags,
1557 vir_bytes addr, socklen_t addr_len)
1559 char buf[UCHAR_MAX + 1];
1560 uint8_t len;
1561 sa_family_t family;
1562 struct sockaddr sa;
1563 struct sockaddr_in sin;
1564 struct sockaddr_in6 sin6;
1565 int all, off, left;
1568 * For UNIX domain sockets, make sure there's always room to add a
1569 * trailing NULL byte, because UDS paths are not necessarily null
1570 * terminated.
1572 if (addr_len < offsetof(struct sockaddr, sa_data) ||
1573 addr_len >= sizeof(buf)) {
1574 put_ptr(proc, name, addr);
1576 return;
1579 if (!put_open_struct(proc, name, flags, addr, buf, addr_len))
1580 return;
1582 memcpy(&sa, buf, sizeof(sa));
1583 len = sa.sa_len;
1584 family = sa.sa_family;
1585 all = (verbose > 1);
1587 switch (family) {
1588 case AF_LOCAL:
1589 if (verbose > 1)
1590 put_value(proc, "sun_len", "%u", len);
1591 if (verbose > 0)
1592 put_socket_family(proc, "sun_family", family);
1593 off = (int)offsetof(struct sockaddr_un, sun_path);
1594 left = addr_len - off;
1595 if (left > 0) {
1596 buf[addr_len] = 0; /* force null termination */
1597 put_buf(proc, "sun_path", PF_LOCADDR | PF_PATH,
1598 (vir_bytes)&buf[off],
1599 left + 1 /* include null byte */);
1601 break;
1602 case AF_INET:
1603 if (verbose > 1)
1604 put_value(proc, "sin_len", "%u", len);
1605 if (verbose > 0)
1606 put_socket_family(proc, "sin_family", family);
1607 if (addr_len == sizeof(sin)) {
1608 memcpy(&sin, buf, sizeof(sin));
1609 put_value(proc, "sin_port", "%u", ntohs(sin.sin_port));
1610 put_in_addr(proc, "sin_addr", sin.sin_addr);
1611 } else
1612 all = FALSE;
1613 break;
1614 case AF_INET6:
1615 if (verbose > 1)
1616 put_value(proc, "sin6_len", "%u", len);
1617 if (verbose > 0)
1618 put_socket_family(proc, "sin6_family", family);
1619 if (addr_len == sizeof(sin6)) {
1620 memcpy(&sin6, buf, sizeof(sin6));
1621 put_value(proc, "sin6_port", "%u",
1622 ntohs(sin6.sin6_port));
1623 if (verbose > 1)
1624 put_value(proc, "sin6_flowinfo", "%"PRIu32,
1625 sin6.sin6_flowinfo);
1626 put_in6_addr(proc, "sin6_addr", &sin6.sin6_addr);
1627 if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
1628 IN6_IS_ADDR_SITELOCAL(&sin6.sin6_addr) ||
1629 verbose > 0)
1630 put_value(proc, "sin6_scope_id", "%"PRIu32,
1631 sin6.sin6_scope_id);
1632 } else
1633 all = FALSE;
1634 break;
1635 /* TODO: support for other address families */
1636 default:
1637 if (verbose > 1)
1638 put_value(proc, "sa_len", "%u", len);
1639 put_socket_family(proc, "sa_family", family);
1640 all = (verbose > 1 && family == AF_UNSPEC);
1643 put_close_struct(proc, all);
1646 /* This function is shared between bind and connect. */
1647 static int
1648 vfs_bind_out(struct trace_proc * proc, const message * m_out)
1651 put_fd(proc, "fd", m_out->m_lc_vfs_sockaddr.fd);
1652 put_struct_sockaddr(proc, "addr", 0, m_out->m_lc_vfs_sockaddr.addr,
1653 m_out->m_lc_vfs_sockaddr.addr_len);
1654 put_value(proc, "addr_len", "%u", m_out->m_lc_vfs_sockaddr.addr_len);
1656 return CT_DONE;
1659 static int
1660 vfs_listen_out(struct trace_proc * proc, const message * m_out)
1663 put_fd(proc, "fd", m_out->m_lc_vfs_listen.fd);
1664 put_value(proc, "backlog", "%d", m_out->m_lc_vfs_listen.backlog);
1666 return CT_DONE;
1669 static int
1670 vfs_accept_out(struct trace_proc * proc, const message * m_out)
1673 put_fd(proc, "fd", m_out->m_lc_vfs_sockaddr.fd);
1675 return CT_NOTDONE;
1678 static void
1679 vfs_accept_in(struct trace_proc * proc, const message * m_out,
1680 const message * m_in, int failed)
1683 put_struct_sockaddr(proc, "addr", failed,
1684 m_out->m_lc_vfs_sockaddr.addr, m_in->m_vfs_lc_socklen.len);
1686 * We print the resulting address length rather than the given buffer
1687 * size here, as we do in recvfrom, getsockname, getpeername, and (less
1688 * explicitly) recvmsg. We could also print both, by adding the
1689 * resulting length after the call result.
1691 if (m_out->m_lc_vfs_sockaddr.addr == 0)
1692 put_field(proc, "addr_len", "NULL");
1693 else if (!failed)
1694 put_value(proc, "addr_len", "{%u}",
1695 m_in->m_vfs_lc_socklen.len);
1696 else
1697 put_field(proc, "addr_len", "&..");
1699 put_equals(proc);
1700 put_result(proc);
1703 static const struct flags msg_flags[] = {
1704 FLAG(MSG_OOB),
1705 FLAG(MSG_PEEK),
1706 FLAG(MSG_DONTROUTE),
1707 FLAG(MSG_EOR),
1708 FLAG(MSG_TRUNC),
1709 FLAG(MSG_CTRUNC),
1710 FLAG(MSG_WAITALL),
1711 FLAG(MSG_DONTWAIT),
1712 FLAG(MSG_BCAST),
1713 FLAG(MSG_MCAST),
1714 #ifdef MSG_NOSIGNAL
1715 FLAG(MSG_NOSIGNAL),
1716 #endif
1717 FLAG(MSG_CMSG_CLOEXEC),
1718 FLAG(MSG_NBIO),
1719 FLAG(MSG_WAITFORONE),
1722 static int
1723 vfs_sendto_out(struct trace_proc * proc, const message * m_out)
1726 put_fd(proc, "fd", m_out->m_lc_vfs_sendrecv.fd);
1727 put_buf(proc, "buf", 0, m_out->m_lc_vfs_sendrecv.buf,
1728 m_out->m_lc_vfs_readwrite.len);
1729 put_value(proc, "len", "%zu", m_out->m_lc_vfs_sendrecv.len);
1730 put_flags(proc, "flags", msg_flags, COUNT(msg_flags), "0x%x",
1731 m_out->m_lc_vfs_sendrecv.flags);
1732 put_struct_sockaddr(proc, "addr", 0, m_out->m_lc_vfs_sendrecv.addr,
1733 m_out->m_lc_vfs_sendrecv.addr_len);
1734 put_value(proc, "addr_len", "%u", m_out->m_lc_vfs_sendrecv.addr_len);
1736 return CT_DONE;
1739 static void
1740 put_struct_iovec(struct trace_proc * proc, const char * name, int flags,
1741 vir_bytes addr, int len, ssize_t bmax)
1743 struct iovec iov;
1744 size_t bytes;
1745 int i, imax;
1748 * For simplicity and clarity reasons, we currently print the I/O
1749 * vector as an array of data elements rather than an array of
1750 * structures. We also copy in each element separately, because as of
1751 * writing there is no system support for more than one element anyway.
1752 * All of this may be changed later.
1754 if ((flags & PF_FAILED) || valuesonly > 1 || addr == 0 || len < 0) {
1755 put_ptr(proc, name, addr);
1757 return;
1760 if (len == 0 || bmax == 0) {
1761 put_field(proc, name, "[]");
1763 return;
1766 /* As per logic below, 'imax' must be set to a nonzero value here. */
1767 if (verbose == 0)
1768 imax = 4;
1769 else if (verbose == 1)
1770 imax = 16;
1771 else
1772 imax = INT_MAX;
1774 for (i = 0; i < len && bmax > 0; i++) {
1775 if (mem_get_data(proc->pid, addr, &iov, sizeof(iov)) < 0) {
1776 if (i == 0) {
1777 put_ptr(proc, name, addr);
1779 return;
1782 len = imax = 0; /* make put_tail() print an error */
1783 break;
1786 if (i == 0)
1787 put_open(proc, name, 0, "[", ", ");
1789 bytes = MIN(iov.iov_len, (size_t)bmax);
1791 if (len < imax)
1792 put_buf(proc, NULL, 0, (vir_bytes)iov.iov_base, bytes);
1794 addr += sizeof(struct iovec);
1795 bmax -= bytes;
1798 if (imax == 0 || imax < len)
1799 put_tail(proc, len, imax);
1800 put_close(proc, "]");
1803 void
1804 put_struct_uucred(struct trace_proc * proc, const char * name, int flags,
1805 vir_bytes addr)
1807 struct uucred cred;
1809 if (!put_open_struct(proc, name, flags, addr, &cred, sizeof(cred)))
1810 return;
1812 put_value(proc, "cr_uid", "%u", cred.cr_uid);
1813 if (verbose > 0) {
1814 put_value(proc, "cr_gid", "%u", cred.cr_gid);
1815 if (verbose > 1)
1816 put_value(proc, "cr_ngroups", "%d", cred.cr_ngroups);
1817 put_groups(proc, "cr_groups", PF_LOCADDR,
1818 (vir_bytes)&cred.cr_groups, cred.cr_ngroups);
1821 put_close_struct(proc, verbose > 0);
1824 static void
1825 put_socket_level(struct trace_proc * proc, const char * name, int level)
1829 * Unfortunately, the level is a domain-specific protocol number. That
1830 * means that without knowing how the socket was created, we cannot
1831 * tell what it means. The only thing we can print is SOL_SOCKET,
1832 * which is the same across all domains.
1834 if (!valuesonly && level == SOL_SOCKET)
1835 put_field(proc, name, "SOL_SOCKET");
1836 else
1837 put_value(proc, name, "%d", level);
1840 void
1841 put_cmsg_type(struct trace_proc * proc, const char * name, int type)
1843 const char *text = NULL;
1845 if (!valuesonly) {
1846 switch (type) {
1847 TEXT(SCM_RIGHTS);
1848 TEXT(SCM_CREDS);
1849 TEXT(SCM_TIMESTAMP);
1853 if (text != NULL)
1854 put_field(proc, name, text);
1855 else
1856 put_value(proc, name, "%d", type);
1859 static void
1860 put_cmsg_rights(struct trace_proc * proc, const char * name, char * buf,
1861 size_t size, char * cptr, size_t chunk, vir_bytes addr, size_t len)
1863 unsigned int i, nfds;
1864 int *ptr;
1866 put_open(proc, name, PF_NONAME, "[", ", ");
1869 * Since file descriptors are important, we print them all, regardless
1870 * of the current verbosity level. Start with the file descriptors
1871 * that are already copied into the local buffer.
1873 ptr = (int *)cptr;
1874 chunk = MIN(chunk, len);
1876 nfds = chunk / sizeof(int);
1877 for (i = 0; i < nfds; i++)
1878 put_fd(proc, NULL, ptr[i]);
1880 /* Then do the remaining file descriptors, in chunks. */
1881 size -= size % sizeof(int);
1883 for (len -= chunk; len >= sizeof(int); len -= chunk) {
1884 chunk = MIN(len, size);
1886 if (mem_get_data(proc->pid, addr, buf, chunk) < 0) {
1887 put_field(proc, NULL, "..");
1889 break;
1892 ptr = (int *)buf;
1893 nfds = chunk / sizeof(int);
1894 for (i = 0; i < nfds; i++)
1895 put_fd(proc, NULL, ptr[i]);
1897 addr += chunk;
1900 put_close(proc, "]");
1903 static void
1904 put_cmsg(struct trace_proc * proc, const char * name, vir_bytes addr,
1905 size_t len)
1907 struct cmsghdr cmsg;
1908 char buf[CMSG_SPACE(sizeof(struct uucred))];
1909 size_t off, chunk, datalen;
1911 if (valuesonly > 1 || addr == 0 || len < CMSG_LEN(0)) {
1912 put_ptr(proc, name, addr);
1914 return;
1917 for (off = 0; off < len; off += CMSG_SPACE(datalen)) {
1918 chunk = MIN(len - off, sizeof(buf));
1920 if (chunk < CMSG_LEN(0))
1921 break;
1923 if (mem_get_data(proc->pid, addr + off, buf, chunk) < 0) {
1924 if (off == 0) {
1925 put_ptr(proc, name, addr);
1927 return;
1929 break;
1932 if (off == 0)
1933 put_open(proc, name, 0, "[", ", ");
1935 memcpy(&cmsg, buf, sizeof(cmsg));
1937 put_open(proc, NULL, 0, "{", ", ");
1938 if (verbose > 0)
1939 put_value(proc, "cmsg_len", "%u", cmsg.cmsg_len);
1940 put_socket_level(proc, "cmsg_level", cmsg.cmsg_level);
1941 if (cmsg.cmsg_level == SOL_SOCKET)
1942 put_cmsg_type(proc, "cmsg_type", cmsg.cmsg_type);
1943 else
1944 put_value(proc, "cmsg_type", "%d", cmsg.cmsg_type);
1946 if (cmsg.cmsg_len < CMSG_LEN(0) || off + cmsg.cmsg_len > len) {
1947 put_tail(proc, 0, 0);
1948 put_close(proc, "}");
1949 break;
1952 datalen = cmsg.cmsg_len - CMSG_LEN(0);
1954 if (cmsg.cmsg_level == SOL_SOCKET &&
1955 cmsg.cmsg_type == SCM_RIGHTS) {
1956 put_cmsg_rights(proc, "cmsg_data", buf, sizeof(buf),
1957 &buf[CMSG_LEN(0)], chunk - CMSG_LEN(0),
1958 addr + off + chunk, datalen);
1959 } else if (cmsg.cmsg_level == SOL_SOCKET &&
1960 cmsg.cmsg_type == SCM_CREDS &&
1961 datalen >= sizeof(struct uucred) &&
1962 chunk >= CMSG_LEN(datalen)) {
1963 put_struct_uucred(proc, "cmsg_data", PF_LOCADDR,
1964 (vir_bytes)&buf[CMSG_LEN(0)]);
1965 } else if (datalen > 0)
1966 put_field(proc, "cmsg_data", "..");
1968 if (verbose == 0)
1969 put_field(proc, NULL, "..");
1970 put_close(proc, "}");
1973 if (off < len)
1974 put_field(proc, NULL, "..");
1975 put_close(proc, "]");
1978 static void
1979 put_struct_msghdr(struct trace_proc * proc, const char * name, int flags,
1980 vir_bytes addr, ssize_t max)
1982 struct msghdr msg;
1983 int all;
1985 if (!put_open_struct(proc, name, flags, addr, &msg, sizeof(msg)))
1986 return;
1988 all = TRUE;
1990 if (msg.msg_name != NULL || verbose > 1) {
1991 put_struct_sockaddr(proc, "msg_name", 0,
1992 (vir_bytes)msg.msg_name, msg.msg_namelen);
1993 if (verbose > 0)
1994 put_value(proc, "msg_namelen", "%u", msg.msg_namelen);
1995 else
1996 all = FALSE;
1997 } else
1998 all = FALSE;
2000 put_struct_iovec(proc, "msg_iov", 0, (vir_bytes)msg.msg_iov,
2001 msg.msg_iovlen, max);
2002 if (verbose > 0)
2003 put_value(proc, "msg_iovlen", "%d", msg.msg_iovlen);
2004 else
2005 all = FALSE;
2007 if (msg.msg_control != NULL || verbose > 1) {
2008 put_cmsg(proc, "msg_control", (vir_bytes)msg.msg_control,
2009 msg.msg_controllen);
2011 if (verbose > 0)
2012 put_value(proc, "msg_controllen", "%u",
2013 msg.msg_controllen);
2014 else
2015 all = FALSE;
2016 } else
2017 all = FALSE;
2019 /* When receiving, print the flags field as well. */
2020 if (flags & PF_ALT)
2021 put_flags(proc, "msg_flags", msg_flags, COUNT(msg_flags),
2022 "0x%x", msg.msg_flags);
2024 put_close_struct(proc, all);
2027 static int
2028 vfs_sendmsg_out(struct trace_proc * proc, const message * m_out)
2031 put_fd(proc, "fd", m_out->m_lc_vfs_sockmsg.fd);
2032 put_struct_msghdr(proc, "msg", 0, m_out->m_lc_vfs_sockmsg.msgbuf,
2033 SSIZE_MAX);
2034 put_flags(proc, "flags", msg_flags, COUNT(msg_flags), "0x%x",
2035 m_out->m_lc_vfs_sockmsg.flags);
2037 return CT_DONE;
2040 static int
2041 vfs_recvfrom_out(struct trace_proc * proc, const message * m_out)
2044 put_fd(proc, "fd", m_out->m_lc_vfs_sendrecv.fd);
2046 return CT_NOTDONE;
2049 static void
2050 vfs_recvfrom_in(struct trace_proc * proc, const message * m_out,
2051 const message * m_in, int failed)
2054 put_buf(proc, "buf", failed, m_out->m_lc_vfs_sendrecv.buf,
2055 m_in->m_type);
2056 put_value(proc, "len", "%zu", m_out->m_lc_vfs_sendrecv.len);
2057 put_flags(proc, "flags", msg_flags, COUNT(msg_flags), "0x%x",
2058 m_out->m_lc_vfs_sendrecv.flags);
2059 put_struct_sockaddr(proc, "addr", failed,
2060 m_out->m_lc_vfs_sendrecv.addr, m_in->m_vfs_lc_socklen.len);
2061 if (m_out->m_lc_vfs_sendrecv.addr == 0)
2062 put_field(proc, "addr_len", "NULL");
2063 else if (!failed)
2064 put_value(proc, "addr_len", "{%u}",
2065 m_in->m_vfs_lc_socklen.len);
2066 else
2067 put_field(proc, "addr_len", "&..");
2069 put_equals(proc);
2070 put_result(proc);
2073 static int
2074 vfs_recvmsg_out(struct trace_proc * proc, const message * m_out)
2077 put_fd(proc, "fd", m_out->m_lc_vfs_sockmsg.fd);
2079 return CT_NOTDONE;
2082 static void
2083 vfs_recvmsg_in(struct trace_proc * proc, const message * m_out,
2084 const message * m_in, int failed)
2088 * We choose to print only the resulting structure in this case. Doing
2089 * so is easier and less messy than printing both the original and the
2090 * result for the fields that are updated by the system (msg_namelen
2091 * and msg_controllen); also, this approach is stateless. Admittedly
2092 * it is not entirely consistent with many other parts of the trace
2093 * output, though.
2095 put_struct_msghdr(proc, "msg", PF_ALT | failed,
2096 m_out->m_lc_vfs_sockmsg.msgbuf, m_in->m_type);
2097 put_flags(proc, "flags", msg_flags, COUNT(msg_flags), "0x%x",
2098 m_out->m_lc_vfs_sockmsg.flags);
2100 put_equals(proc);
2101 put_result(proc);
2104 static void
2105 put_sockopt_name(struct trace_proc * proc, const char * name, int level,
2106 int optname)
2108 const char *text = NULL;
2111 * The only level for which we can know names is SOL_SOCKET. See also
2112 * put_socket_level(). Of course we could guess, but then we need a
2113 * proper guessing system, which should probably also take into account
2114 * the [gs]etsockopt option length. TODO.
2116 if (!valuesonly && level == SOL_SOCKET) {
2117 switch (optname) {
2118 TEXT(SO_DEBUG);
2119 TEXT(SO_ACCEPTCONN);
2120 TEXT(SO_REUSEADDR);
2121 TEXT(SO_KEEPALIVE);
2122 TEXT(SO_DONTROUTE);
2123 TEXT(SO_BROADCAST);
2124 TEXT(SO_USELOOPBACK);
2125 TEXT(SO_LINGER);
2126 TEXT(SO_OOBINLINE);
2127 TEXT(SO_REUSEPORT);
2128 TEXT(SO_NOSIGPIPE);
2129 TEXT(SO_TIMESTAMP);
2130 TEXT(SO_PASSCRED);
2131 TEXT(SO_PEERCRED);
2132 TEXT(SO_SNDBUF);
2133 TEXT(SO_RCVBUF);
2134 TEXT(SO_SNDLOWAT);
2135 TEXT(SO_RCVLOWAT);
2136 TEXT(SO_ERROR);
2137 TEXT(SO_TYPE);
2138 TEXT(SO_OVERFLOWED);
2139 TEXT(SO_NOHEADER);
2140 TEXT(SO_SNDTIMEO);
2141 TEXT(SO_RCVTIMEO);
2145 if (text != NULL)
2146 put_field(proc, name, text);
2147 else
2148 put_value(proc, name, "0x%x", optname);
2151 static void
2152 put_sockopt_data(struct trace_proc * proc, const char * name, int flags,
2153 int level, int optname, vir_bytes addr, socklen_t len)
2155 const char *text;
2156 int i;
2157 struct linger l;
2158 struct uucred cr;
2159 struct timeval tv;
2160 void *ptr;
2161 size_t size;
2163 /* See above regarding ambiguity for levels other than SOL_SOCKET. */
2164 if ((flags & PF_FAILED) || valuesonly > 1 || len == 0 ||
2165 level != SOL_SOCKET) {
2166 put_ptr(proc, name, addr);
2168 return;
2171 /* Determine how much data to get, and where to put it. */
2172 switch (optname) {
2173 case SO_DEBUG:
2174 case SO_ACCEPTCONN:
2175 case SO_REUSEADDR:
2176 case SO_KEEPALIVE:
2177 case SO_DONTROUTE:
2178 case SO_BROADCAST:
2179 case SO_USELOOPBACK:
2180 case SO_OOBINLINE:
2181 case SO_REUSEPORT:
2182 case SO_NOSIGPIPE:
2183 case SO_TIMESTAMP:
2184 case SO_PASSCRED:
2185 case SO_SNDBUF:
2186 case SO_RCVBUF:
2187 case SO_SNDLOWAT:
2188 case SO_RCVLOWAT:
2189 case SO_ERROR:
2190 case SO_TYPE:
2191 case SO_OVERFLOWED:
2192 case SO_NOHEADER:
2193 ptr = &i;
2194 size = sizeof(i);
2195 break;
2196 case SO_LINGER:
2197 ptr = &l;
2198 size = sizeof(l);
2199 break;
2200 case SO_PEERCRED:
2201 ptr = &cr;
2202 size = sizeof(cr);
2203 break;
2204 case SO_SNDTIMEO:
2205 case SO_RCVTIMEO:
2206 ptr = &tv;
2207 size = sizeof(tv);
2208 break;
2209 default:
2210 put_ptr(proc, name, addr);
2211 return;
2214 /* Get the data. Do not bother with truncated values. */
2215 if (len < size || mem_get_data(proc->pid, addr, ptr, size) < 0) {
2216 put_ptr(proc, name, addr);
2218 return;
2221 /* Print the data according to the option name. */
2222 switch (optname) {
2223 case SO_LINGER:
2224 /* This isn't going to appear anywhere else; do it inline. */
2225 put_open(proc, name, 0, "{", ", ");
2226 put_value(proc, "l_onoff", "%d", l.l_onoff);
2227 put_value(proc, "l_linger", "%d", l.l_linger);
2228 put_close(proc, "}");
2229 break;
2230 case SO_PEERCRED:
2231 put_struct_uucred(proc, name, PF_LOCADDR, (vir_bytes)&cr);
2232 break;
2233 case SO_ERROR:
2234 put_open(proc, name, 0, "{", ", ");
2235 if (!valuesonly && (text = get_error_name(i)) != NULL)
2236 put_field(proc, NULL, text);
2237 else
2238 put_value(proc, NULL, "%d", i);
2239 put_close(proc, "}");
2240 break;
2241 case SO_TYPE:
2242 put_open(proc, name, 0, "{", ", ");
2243 put_socket_type(proc, NULL, i);
2244 put_close(proc, "}");
2245 break;
2246 case SO_SNDTIMEO:
2247 case SO_RCVTIMEO:
2248 put_struct_timeval(proc, name, PF_LOCADDR, (vir_bytes)&tv);
2249 break;
2250 default:
2251 /* All other options are integer values. */
2252 put_value(proc, name, "{%d}", i);
2256 static int
2257 vfs_setsockopt_out(struct trace_proc * proc, const message * m_out)
2259 int level, name;
2261 level = m_out->m_lc_vfs_sockopt.level;
2262 name = m_out->m_lc_vfs_sockopt.name;
2264 put_fd(proc, "fd", m_out->m_lc_vfs_sockopt.fd);
2265 put_socket_level(proc, "level", level);
2266 put_sockopt_name(proc, "name", level, name);
2267 put_sockopt_data(proc, "buf", 0, level, name,
2268 m_out->m_lc_vfs_sockopt.buf, m_out->m_lc_vfs_sockopt.len);
2269 put_value(proc, "len", "%u", m_out->m_lc_vfs_sockopt.len);
2271 return CT_DONE;
2274 static int
2275 vfs_getsockopt_out(struct trace_proc * proc, const message * m_out)
2277 int level;
2279 level = m_out->m_lc_vfs_sockopt.level;
2281 put_fd(proc, "fd", m_out->m_lc_vfs_sockopt.fd);
2282 put_socket_level(proc, "level", level);
2283 put_sockopt_name(proc, "name", level, m_out->m_lc_vfs_sockopt.name);
2285 return CT_NOTDONE;
2288 static void
2289 vfs_getsockopt_in(struct trace_proc * proc, const message * m_out,
2290 const message * m_in, int failed)
2293 put_sockopt_data(proc, "buf", failed, m_out->m_lc_vfs_sockopt.level,
2294 m_out->m_lc_vfs_sockopt.name, m_out->m_lc_vfs_sockopt.buf,
2295 m_in->m_vfs_lc_socklen.len);
2297 * For the length, we follow the same scheme as for addr_len pointers
2298 * in accept() et al., in that we print the result only. We need not
2299 * take into account that the given buffer is NULL as it must not be.
2301 if (!failed)
2302 put_value(proc, "len", "%u", m_out->m_lc_vfs_sockopt.len);
2303 else
2304 put_field(proc, "len", "&..");
2306 put_equals(proc);
2307 put_result(proc);
2310 /* This function is shared between getsockname and getpeername. */
2311 static int
2312 vfs_getsockname_out(struct trace_proc * proc, const message * m_out)
2315 put_fd(proc, "fd", m_out->m_lc_vfs_sockaddr.fd);
2317 return CT_NOTDONE;
2320 static void
2321 vfs_getsockname_in(struct trace_proc * proc, const message * m_out,
2322 const message * m_in, int failed)
2325 put_struct_sockaddr(proc, "addr", failed,
2326 m_out->m_lc_vfs_sockaddr.addr, m_in->m_vfs_lc_socklen.len);
2327 if (m_out->m_lc_vfs_sockaddr.addr == 0)
2328 put_field(proc, "addr_len", "NULL");
2329 else if (!failed)
2330 put_value(proc, "addr_len", "{%u}",
2331 m_in->m_vfs_lc_socklen.len);
2332 else
2333 put_field(proc, "addr_len", "&..");
2335 put_equals(proc);
2336 put_result(proc);
2339 void
2340 put_shutdown_how(struct trace_proc * proc, const char * name, int how)
2342 const char *text = NULL;
2344 if (!valuesonly) {
2345 switch (how) {
2346 TEXT(SHUT_RD);
2347 TEXT(SHUT_WR);
2348 TEXT(SHUT_RDWR);
2352 if (text != NULL)
2353 put_field(proc, name, text);
2354 else
2355 put_value(proc, name, "%d", how);
2358 static int
2359 vfs_shutdown_out(struct trace_proc * proc, const message * m_out)
2362 put_fd(proc, "fd", m_out->m_lc_vfs_shutdown.fd);
2363 put_shutdown_how(proc, "how", m_out->m_lc_vfs_shutdown.how);
2365 return CT_DONE;
2368 #define VFS_CALL(c) [((VFS_ ## c) - VFS_BASE)]
2370 static const struct call_handler vfs_map[] = {
2371 VFS_CALL(READ) = HANDLER("read", vfs_read_out, vfs_read_in),
2372 VFS_CALL(WRITE) = HANDLER("write", vfs_write_out, default_in),
2373 VFS_CALL(LSEEK) = HANDLER("lseek", vfs_lseek_out, vfs_lseek_in),
2374 VFS_CALL(OPEN) = HANDLER("open", vfs_open_out, vfs_open_in),
2375 VFS_CALL(CREAT) = HANDLER("open", vfs_creat_out, vfs_open_in),
2376 VFS_CALL(CLOSE) = HANDLER("close", vfs_close_out, default_in),
2377 VFS_CALL(LINK) = HANDLER("link", vfs_link_out, default_in),
2378 VFS_CALL(UNLINK) = HANDLER("unlink", vfs_path_out, default_in),
2379 VFS_CALL(CHDIR) = HANDLER("chdir", vfs_path_out, default_in),
2380 VFS_CALL(MKDIR) = HANDLER("mkdir", vfs_path_mode_out, default_in),
2381 VFS_CALL(MKNOD) = HANDLER("mknod", vfs_mknod_out, default_in),
2382 VFS_CALL(CHMOD) = HANDLER("chmod", vfs_path_mode_out, default_in),
2383 VFS_CALL(CHOWN) = HANDLER("chown", vfs_chown_out, default_in),
2384 VFS_CALL(MOUNT) = HANDLER("mount", vfs_mount_out, default_in),
2385 VFS_CALL(UMOUNT) = HANDLER("umount", vfs_umount_out, vfs_umount_in),
2386 VFS_CALL(ACCESS) = HANDLER("access", vfs_access_out, default_in),
2387 VFS_CALL(SYNC) = HANDLER("sync", default_out, default_in),
2388 VFS_CALL(RENAME) = HANDLER("rename", vfs_link_out, default_in),
2389 VFS_CALL(RMDIR) = HANDLER("rmdir", vfs_path_out, default_in),
2390 VFS_CALL(SYMLINK) = HANDLER("symlink", vfs_link_out, default_in),
2391 VFS_CALL(READLINK) = HANDLER("readlink", vfs_readlink_out,
2392 vfs_readlink_in),
2393 VFS_CALL(STAT) = HANDLER("stat", vfs_stat_out, vfs_stat_in),
2394 VFS_CALL(FSTAT) = HANDLER("fstat", vfs_fstat_out, vfs_fstat_in),
2395 VFS_CALL(LSTAT) = HANDLER("lstat", vfs_stat_out, vfs_stat_in),
2396 VFS_CALL(IOCTL) = HANDLER("ioctl", vfs_ioctl_out, vfs_ioctl_in),
2397 VFS_CALL(FCNTL) = HANDLER("fcntl", vfs_fcntl_out, vfs_fcntl_in),
2398 VFS_CALL(PIPE2) = HANDLER("pipe2", vfs_pipe2_out, vfs_pipe2_in),
2399 VFS_CALL(UMASK) = HANDLER("umask", vfs_umask_out, vfs_umask_in),
2400 VFS_CALL(CHROOT) = HANDLER("chroot", vfs_path_out, default_in),
2401 VFS_CALL(GETDENTS) = HANDLER("getdents", vfs_getdents_out,
2402 vfs_getdents_in),
2403 VFS_CALL(SELECT) = HANDLER("select", vfs_select_out, vfs_select_in),
2404 VFS_CALL(FCHDIR) = HANDLER("fchdir", vfs_fchdir_out, default_in),
2405 VFS_CALL(FSYNC) = HANDLER("fsync", vfs_fsync_out, default_in),
2406 VFS_CALL(TRUNCATE) = HANDLER("truncate", vfs_truncate_out, default_in),
2407 VFS_CALL(FTRUNCATE) = HANDLER("ftruncate", vfs_ftruncate_out,
2408 default_in),
2409 VFS_CALL(FCHMOD) = HANDLER("fchmod", vfs_fchmod_out, default_in),
2410 VFS_CALL(FCHOWN) = HANDLER("fchown", vfs_fchown_out, default_in),
2411 VFS_CALL(UTIMENS) = HANDLER_NAME(vfs_utimens_name, vfs_utimens_out,
2412 default_in),
2413 VFS_CALL(GETVFSSTAT) = HANDLER("getvfsstat", vfs_getvfsstat_out,
2414 vfs_getvfsstat_in),
2415 VFS_CALL(STATVFS1) = HANDLER("statvfs1", vfs_statvfs1_out,
2416 vfs_statvfs1_in),
2417 VFS_CALL(FSTATVFS1) = HANDLER("fstatvfs1", vfs_fstatvfs1_out,
2418 vfs_statvfs1_in),
2419 VFS_CALL(SVRCTL) = HANDLER("vfs_svrctl", vfs_svrctl_out,
2420 vfs_svrctl_in),
2421 VFS_CALL(GCOV_FLUSH) = HANDLER("gcov_flush", vfs_gcov_flush_out,
2422 default_in),
2423 VFS_CALL(SOCKET) = HANDLER("socket", vfs_socket_out, default_in),
2424 VFS_CALL(SOCKETPAIR) = HANDLER("socketpair", vfs_socketpair_out,
2425 vfs_socketpair_in),
2426 VFS_CALL(BIND) = HANDLER("bind", vfs_bind_out, default_in),
2427 VFS_CALL(CONNECT) = HANDLER("connect", vfs_bind_out, default_in),
2428 VFS_CALL(LISTEN) = HANDLER("listen", vfs_listen_out, default_in),
2429 VFS_CALL(ACCEPT) = HANDLER("accept", vfs_accept_out, vfs_accept_in),
2430 VFS_CALL(SENDTO) = HANDLER("sendto", vfs_sendto_out, default_in),
2431 VFS_CALL(SENDMSG) = HANDLER("sendmsg", vfs_sendmsg_out, default_in),
2432 VFS_CALL(RECVFROM) = HANDLER("recvfrom", vfs_recvfrom_out,
2433 vfs_recvfrom_in),
2434 VFS_CALL(RECVMSG) = HANDLER("recvmsg", vfs_recvmsg_out,
2435 vfs_recvmsg_in),
2436 VFS_CALL(SETSOCKOPT) = HANDLER("setsockopt", vfs_setsockopt_out,
2437 default_in),
2438 VFS_CALL(GETSOCKOPT) = HANDLER("getsockopt", vfs_getsockopt_out,
2439 vfs_getsockopt_in),
2440 VFS_CALL(GETSOCKNAME) = HANDLER("getsockname", vfs_getsockname_out,
2441 vfs_getsockname_in),
2442 VFS_CALL(GETPEERNAME) = HANDLER("getpeername", vfs_getsockname_out,
2443 vfs_getsockname_in),
2444 VFS_CALL(SHUTDOWN) = HANDLER("shutdown", vfs_shutdown_out, default_in),
2447 const struct calls vfs_calls = {
2448 .endpt = VFS_PROC_NR,
2449 .base = VFS_BASE,
2450 .map = vfs_map,
2451 .count = COUNT(vfs_map)