1*12904384SSimon J. Gerraty /* $NetBSD: filemon_ktrace.c,v 1.15 2021/07/31 09:30:17 rillig Exp $ */
249caa483SSimon J. Gerraty
3dba7b0efSSimon J. Gerraty /*
449caa483SSimon J. Gerraty * Copyright (c) 2019 The NetBSD Foundation, Inc.
549caa483SSimon J. Gerraty * All rights reserved.
649caa483SSimon J. Gerraty *
749caa483SSimon J. Gerraty * This code is derived from software contributed to The NetBSD Foundation
849caa483SSimon J. Gerraty * by Taylor R. Campbell.
949caa483SSimon J. Gerraty *
1049caa483SSimon J. Gerraty * Redistribution and use in source and binary forms, with or without
1149caa483SSimon J. Gerraty * modification, are permitted provided that the following conditions
1249caa483SSimon J. Gerraty * are met:
1349caa483SSimon J. Gerraty * 1. Redistributions of source code must retain the above copyright
1449caa483SSimon J. Gerraty * notice, this list of conditions and the following disclaimer.
1549caa483SSimon J. Gerraty * 2. Redistributions in binary form must reproduce the above copyright
1649caa483SSimon J. Gerraty * notice, this list of conditions and the following disclaimer in the
1749caa483SSimon J. Gerraty * documentation and/or other materials provided with the distribution.
1849caa483SSimon J. Gerraty *
1949caa483SSimon J. Gerraty * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2049caa483SSimon J. Gerraty * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2149caa483SSimon J. Gerraty * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2249caa483SSimon J. Gerraty * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2349caa483SSimon J. Gerraty * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2449caa483SSimon J. Gerraty * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2549caa483SSimon J. Gerraty * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2649caa483SSimon J. Gerraty * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2749caa483SSimon J. Gerraty * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2849caa483SSimon J. Gerraty * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2949caa483SSimon J. Gerraty * POSSIBILITY OF SUCH DAMAGE.
3049caa483SSimon J. Gerraty */
3149caa483SSimon J. Gerraty
3249caa483SSimon J. Gerraty #define _KERNTYPES /* register_t */
3349caa483SSimon J. Gerraty
3449caa483SSimon J. Gerraty #include "filemon.h"
3549caa483SSimon J. Gerraty
3649caa483SSimon J. Gerraty #include <sys/param.h>
3749caa483SSimon J. Gerraty #include <sys/types.h>
3849caa483SSimon J. Gerraty #include <sys/rbtree.h>
3949caa483SSimon J. Gerraty #include <sys/syscall.h>
4049caa483SSimon J. Gerraty #include <sys/time.h>
4149caa483SSimon J. Gerraty #include <sys/uio.h>
4249caa483SSimon J. Gerraty #include <sys/wait.h>
4349caa483SSimon J. Gerraty
4449caa483SSimon J. Gerraty #include <sys/ktrace.h>
4549caa483SSimon J. Gerraty
4649caa483SSimon J. Gerraty #include <assert.h>
4749caa483SSimon J. Gerraty #include <err.h>
4849caa483SSimon J. Gerraty #include <errno.h>
4949caa483SSimon J. Gerraty #include <fcntl.h>
5049caa483SSimon J. Gerraty #include <stdbool.h>
5149caa483SSimon J. Gerraty #include <stddef.h>
5249caa483SSimon J. Gerraty #include <stdio.h>
5349caa483SSimon J. Gerraty #include <stdlib.h>
5449caa483SSimon J. Gerraty #include <string.h>
5549caa483SSimon J. Gerraty #include <unistd.h>
5649caa483SSimon J. Gerraty
5749caa483SSimon J. Gerraty #ifndef AT_CWD
5849caa483SSimon J. Gerraty #define AT_CWD -1
5949caa483SSimon J. Gerraty #endif
6049caa483SSimon J. Gerraty
6149caa483SSimon J. Gerraty struct filemon;
6249caa483SSimon J. Gerraty struct filemon_key;
6349caa483SSimon J. Gerraty struct filemon_state;
6449caa483SSimon J. Gerraty
6549caa483SSimon J. Gerraty typedef struct filemon_state *filemon_syscall_t(struct filemon *,
6649caa483SSimon J. Gerraty const struct filemon_key *, const struct ktr_syscall *);
6749caa483SSimon J. Gerraty
6849caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_chdir;
6949caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_execve;
7049caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_exit;
7149caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_fork;
7249caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_link;
7349caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_open;
7449caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_openat;
7549caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_symlink;
7649caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_unlink;
7749caa483SSimon J. Gerraty static filemon_syscall_t filemon_sys_rename;
7849caa483SSimon J. Gerraty
7949caa483SSimon J. Gerraty static filemon_syscall_t *const filemon_syscalls[] = {
8049caa483SSimon J. Gerraty [SYS_chdir] = &filemon_sys_chdir,
8149caa483SSimon J. Gerraty [SYS_execve] = &filemon_sys_execve,
8249caa483SSimon J. Gerraty [SYS_exit] = &filemon_sys_exit,
8349caa483SSimon J. Gerraty [SYS_fork] = &filemon_sys_fork,
8449caa483SSimon J. Gerraty [SYS_link] = &filemon_sys_link,
8549caa483SSimon J. Gerraty [SYS_open] = &filemon_sys_open,
8649caa483SSimon J. Gerraty [SYS_openat] = &filemon_sys_openat,
8749caa483SSimon J. Gerraty [SYS_symlink] = &filemon_sys_symlink,
8849caa483SSimon J. Gerraty [SYS_unlink] = &filemon_sys_unlink,
8949caa483SSimon J. Gerraty [SYS_rename] = &filemon_sys_rename,
9049caa483SSimon J. Gerraty };
9149caa483SSimon J. Gerraty
9249caa483SSimon J. Gerraty struct filemon {
9349caa483SSimon J. Gerraty int ktrfd; /* kernel writes ktrace events here */
9449caa483SSimon J. Gerraty FILE *in; /* we read ktrace events from here */
9549caa483SSimon J. Gerraty FILE *out; /* we write filemon events to here */
9649caa483SSimon J. Gerraty rb_tree_t active;
9749caa483SSimon J. Gerraty pid_t child;
9849caa483SSimon J. Gerraty
9949caa483SSimon J. Gerraty /* I/O state machine. */
10049caa483SSimon J. Gerraty enum {
10149caa483SSimon J. Gerraty FILEMON_START = 0,
10249caa483SSimon J. Gerraty FILEMON_HEADER,
10349caa483SSimon J. Gerraty FILEMON_PAYLOAD,
10449caa483SSimon J. Gerraty FILEMON_ERROR,
10549caa483SSimon J. Gerraty } state;
10649caa483SSimon J. Gerraty unsigned char *p;
10749caa483SSimon J. Gerraty size_t resid;
10849caa483SSimon J. Gerraty
10949caa483SSimon J. Gerraty /* I/O buffer. */
11049caa483SSimon J. Gerraty struct ktr_header hdr;
11149caa483SSimon J. Gerraty union {
11249caa483SSimon J. Gerraty struct ktr_syscall syscall;
11349caa483SSimon J. Gerraty struct ktr_sysret sysret;
11449caa483SSimon J. Gerraty char namei[PATH_MAX];
11549caa483SSimon J. Gerraty unsigned char buf[4096];
11649caa483SSimon J. Gerraty } payload;
11749caa483SSimon J. Gerraty };
11849caa483SSimon J. Gerraty
11949caa483SSimon J. Gerraty struct filemon_state {
12049caa483SSimon J. Gerraty struct filemon_key {
12149caa483SSimon J. Gerraty pid_t pid;
12249caa483SSimon J. Gerraty lwpid_t lid;
12349caa483SSimon J. Gerraty } key;
12449caa483SSimon J. Gerraty struct rb_node node;
12549caa483SSimon J. Gerraty int syscode;
12649caa483SSimon J. Gerraty void (*show)(struct filemon *, const struct filemon_state *,
12749caa483SSimon J. Gerraty const struct ktr_sysret *);
12849caa483SSimon J. Gerraty unsigned i;
12949caa483SSimon J. Gerraty unsigned npath;
13049caa483SSimon J. Gerraty char *path[/*npath*/];
13149caa483SSimon J. Gerraty };
13249caa483SSimon J. Gerraty
13306b9b3e0SSimon J. Gerraty /*ARGSUSED*/
13449caa483SSimon J. Gerraty static int
compare_filemon_states(void * cookie,const void * na,const void * nb)13549caa483SSimon J. Gerraty compare_filemon_states(void *cookie, const void *na, const void *nb)
13649caa483SSimon J. Gerraty {
13749caa483SSimon J. Gerraty const struct filemon_state *Sa = na;
13849caa483SSimon J. Gerraty const struct filemon_state *Sb = nb;
13949caa483SSimon J. Gerraty
14049caa483SSimon J. Gerraty if (Sa->key.pid < Sb->key.pid)
14149caa483SSimon J. Gerraty return -1;
14249caa483SSimon J. Gerraty if (Sa->key.pid > Sb->key.pid)
14349caa483SSimon J. Gerraty return +1;
14449caa483SSimon J. Gerraty if (Sa->key.lid < Sb->key.lid)
14549caa483SSimon J. Gerraty return -1;
14649caa483SSimon J. Gerraty if (Sa->key.lid > Sb->key.lid)
14749caa483SSimon J. Gerraty return +1;
14849caa483SSimon J. Gerraty return 0;
14949caa483SSimon J. Gerraty }
15049caa483SSimon J. Gerraty
15106b9b3e0SSimon J. Gerraty /*ARGSUSED*/
15249caa483SSimon J. Gerraty static int
compare_filemon_key(void * cookie,const void * n,const void * k)15349caa483SSimon J. Gerraty compare_filemon_key(void *cookie, const void *n, const void *k)
15449caa483SSimon J. Gerraty {
15549caa483SSimon J. Gerraty const struct filemon_state *S = n;
15649caa483SSimon J. Gerraty const struct filemon_key *key = k;
15749caa483SSimon J. Gerraty
15849caa483SSimon J. Gerraty if (S->key.pid < key->pid)
15949caa483SSimon J. Gerraty return -1;
16049caa483SSimon J. Gerraty if (S->key.pid > key->pid)
16149caa483SSimon J. Gerraty return +1;
16249caa483SSimon J. Gerraty if (S->key.lid < key->lid)
16349caa483SSimon J. Gerraty return -1;
16449caa483SSimon J. Gerraty if (S->key.lid > key->lid)
16549caa483SSimon J. Gerraty return +1;
16649caa483SSimon J. Gerraty return 0;
16749caa483SSimon J. Gerraty }
16849caa483SSimon J. Gerraty
16949caa483SSimon J. Gerraty static const rb_tree_ops_t filemon_rb_ops = {
17049caa483SSimon J. Gerraty .rbto_compare_nodes = &compare_filemon_states,
17149caa483SSimon J. Gerraty .rbto_compare_key = &compare_filemon_key,
17249caa483SSimon J. Gerraty .rbto_node_offset = offsetof(struct filemon_state, node),
17349caa483SSimon J. Gerraty .rbto_context = NULL,
17449caa483SSimon J. Gerraty };
17549caa483SSimon J. Gerraty
17649caa483SSimon J. Gerraty /*
17749caa483SSimon J. Gerraty * filemon_path()
17849caa483SSimon J. Gerraty *
17949caa483SSimon J. Gerraty * Return a pointer to a constant string denoting the `path' of
18049caa483SSimon J. Gerraty * the filemon.
18149caa483SSimon J. Gerraty */
18249caa483SSimon J. Gerraty const char *
filemon_path(void)18349caa483SSimon J. Gerraty filemon_path(void)
18449caa483SSimon J. Gerraty {
18549caa483SSimon J. Gerraty
18649caa483SSimon J. Gerraty return "ktrace";
18749caa483SSimon J. Gerraty }
18849caa483SSimon J. Gerraty
18949caa483SSimon J. Gerraty /*
19049caa483SSimon J. Gerraty * filemon_open()
19149caa483SSimon J. Gerraty *
19249caa483SSimon J. Gerraty * Allocate a filemon descriptor. Returns NULL and sets errno on
19349caa483SSimon J. Gerraty * failure.
19449caa483SSimon J. Gerraty */
19549caa483SSimon J. Gerraty struct filemon *
filemon_open(void)19649caa483SSimon J. Gerraty filemon_open(void)
19749caa483SSimon J. Gerraty {
19849caa483SSimon J. Gerraty struct filemon *F;
19949caa483SSimon J. Gerraty int ktrpipe[2];
20049caa483SSimon J. Gerraty int error;
20149caa483SSimon J. Gerraty
20249caa483SSimon J. Gerraty /* Allocate and zero a struct filemon object. */
203e2eeea75SSimon J. Gerraty F = calloc(1, sizeof *F);
20449caa483SSimon J. Gerraty if (F == NULL)
20549caa483SSimon J. Gerraty return NULL;
20649caa483SSimon J. Gerraty
20749caa483SSimon J. Gerraty /* Create a pipe for ktrace events. */
20849caa483SSimon J. Gerraty if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) {
20949caa483SSimon J. Gerraty error = errno;
21049caa483SSimon J. Gerraty goto fail0;
21149caa483SSimon J. Gerraty }
21249caa483SSimon J. Gerraty
21349caa483SSimon J. Gerraty /* Create a file stream for reading the ktrace events. */
21449caa483SSimon J. Gerraty if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) {
21549caa483SSimon J. Gerraty error = errno;
21649caa483SSimon J. Gerraty goto fail1;
21749caa483SSimon J. Gerraty }
21849caa483SSimon J. Gerraty ktrpipe[0] = -1; /* claimed by fdopen */
21949caa483SSimon J. Gerraty
22049caa483SSimon J. Gerraty /*
22149caa483SSimon J. Gerraty * Set the fd for writing ktrace events and initialize the
22249caa483SSimon J. Gerraty * rbtree. The rest can be safely initialized to zero.
22349caa483SSimon J. Gerraty */
22449caa483SSimon J. Gerraty F->ktrfd = ktrpipe[1];
22549caa483SSimon J. Gerraty rb_tree_init(&F->active, &filemon_rb_ops);
22649caa483SSimon J. Gerraty
22749caa483SSimon J. Gerraty /* Success! */
22849caa483SSimon J. Gerraty return F;
22949caa483SSimon J. Gerraty
23049caa483SSimon J. Gerraty fail1: (void)close(ktrpipe[0]);
23149caa483SSimon J. Gerraty (void)close(ktrpipe[1]);
23249caa483SSimon J. Gerraty fail0: free(F);
23349caa483SSimon J. Gerraty errno = error;
23449caa483SSimon J. Gerraty return NULL;
23549caa483SSimon J. Gerraty }
23649caa483SSimon J. Gerraty
23749caa483SSimon J. Gerraty /*
23849caa483SSimon J. Gerraty * filemon_closefd(F)
23949caa483SSimon J. Gerraty *
24049caa483SSimon J. Gerraty * Internal subroutine to try to flush and close the output file.
24149caa483SSimon J. Gerraty * If F is not open for output, do nothing. Never leaves F open
24249caa483SSimon J. Gerraty * for output even on failure. Returns 0 on success; sets errno
24349caa483SSimon J. Gerraty * and return -1 on failure.
24449caa483SSimon J. Gerraty */
24549caa483SSimon J. Gerraty static int
filemon_closefd(struct filemon * F)24649caa483SSimon J. Gerraty filemon_closefd(struct filemon *F)
24749caa483SSimon J. Gerraty {
24849caa483SSimon J. Gerraty int error = 0;
24949caa483SSimon J. Gerraty
25049caa483SSimon J. Gerraty /* If we're not open, nothing to do. */
25149caa483SSimon J. Gerraty if (F->out == NULL)
25249caa483SSimon J. Gerraty return 0;
25349caa483SSimon J. Gerraty
25449caa483SSimon J. Gerraty /*
25549caa483SSimon J. Gerraty * Flush it, close it, and null it unconditionally, but be
25649caa483SSimon J. Gerraty * careful to return the earliest error in errno.
25749caa483SSimon J. Gerraty */
25849caa483SSimon J. Gerraty if (fflush(F->out) == EOF && error == 0)
25949caa483SSimon J. Gerraty error = errno;
26049caa483SSimon J. Gerraty if (fclose(F->out) == EOF && error == 0)
26149caa483SSimon J. Gerraty error = errno;
26249caa483SSimon J. Gerraty F->out = NULL;
26349caa483SSimon J. Gerraty
26449caa483SSimon J. Gerraty /* Set errno and return -1 if anything went wrong. */
26506b9b3e0SSimon J. Gerraty if (error != 0) {
26649caa483SSimon J. Gerraty errno = error;
26749caa483SSimon J. Gerraty return -1;
26849caa483SSimon J. Gerraty }
26949caa483SSimon J. Gerraty
27049caa483SSimon J. Gerraty /* Success! */
27149caa483SSimon J. Gerraty return 0;
27249caa483SSimon J. Gerraty }
27349caa483SSimon J. Gerraty
27449caa483SSimon J. Gerraty /*
27549caa483SSimon J. Gerraty * filemon_setfd(F, fd)
27649caa483SSimon J. Gerraty *
27749caa483SSimon J. Gerraty * Cause filemon activity on F to be sent to fd. Claims ownership
27849caa483SSimon J. Gerraty * of fd; caller should not use fd afterward, and any duplicates
27949caa483SSimon J. Gerraty * of fd may see their file positions changed.
28049caa483SSimon J. Gerraty */
28149caa483SSimon J. Gerraty int
filemon_setfd(struct filemon * F,int fd)28249caa483SSimon J. Gerraty filemon_setfd(struct filemon *F, int fd)
28349caa483SSimon J. Gerraty {
28449caa483SSimon J. Gerraty
28549caa483SSimon J. Gerraty /*
28649caa483SSimon J. Gerraty * Close an existing output file if done. Fail now if there's
28749caa483SSimon J. Gerraty * an error closing.
28849caa483SSimon J. Gerraty */
28949caa483SSimon J. Gerraty if ((filemon_closefd(F)) == -1)
29049caa483SSimon J. Gerraty return -1;
29149caa483SSimon J. Gerraty assert(F->out == NULL);
29249caa483SSimon J. Gerraty
29349caa483SSimon J. Gerraty /* Open a file stream and claim ownership of the fd. */
29449caa483SSimon J. Gerraty if ((F->out = fdopen(fd, "a")) == NULL)
29549caa483SSimon J. Gerraty return -1;
29649caa483SSimon J. Gerraty
29749caa483SSimon J. Gerraty /*
29849caa483SSimon J. Gerraty * Print the opening output. Any failure will be deferred
29949caa483SSimon J. Gerraty * until closing. For hysterical raisins, we show the parent
30049caa483SSimon J. Gerraty * pid, not the child pid.
30149caa483SSimon J. Gerraty */
30249caa483SSimon J. Gerraty fprintf(F->out, "# filemon version 4\n");
30349caa483SSimon J. Gerraty fprintf(F->out, "# Target pid %jd\n", (intmax_t)getpid());
30449caa483SSimon J. Gerraty fprintf(F->out, "V 4\n");
30549caa483SSimon J. Gerraty
30649caa483SSimon J. Gerraty /* Success! */
30749caa483SSimon J. Gerraty return 0;
30849caa483SSimon J. Gerraty }
30949caa483SSimon J. Gerraty
31049caa483SSimon J. Gerraty /*
31149caa483SSimon J. Gerraty * filemon_setpid_parent(F, pid)
31249caa483SSimon J. Gerraty *
31349caa483SSimon J. Gerraty * Set the traced pid, from the parent. Never fails.
31449caa483SSimon J. Gerraty */
31549caa483SSimon J. Gerraty void
filemon_setpid_parent(struct filemon * F,pid_t pid)31649caa483SSimon J. Gerraty filemon_setpid_parent(struct filemon *F, pid_t pid)
31749caa483SSimon J. Gerraty {
31849caa483SSimon J. Gerraty
31949caa483SSimon J. Gerraty F->child = pid;
32049caa483SSimon J. Gerraty }
32149caa483SSimon J. Gerraty
32249caa483SSimon J. Gerraty /*
32349caa483SSimon J. Gerraty * filemon_setpid_child(F, pid)
32449caa483SSimon J. Gerraty *
32549caa483SSimon J. Gerraty * Set the traced pid, from the child. Returns 0 on success; sets
32649caa483SSimon J. Gerraty * errno and returns -1 on failure.
32749caa483SSimon J. Gerraty */
32849caa483SSimon J. Gerraty int
filemon_setpid_child(const struct filemon * F,pid_t pid)32949caa483SSimon J. Gerraty filemon_setpid_child(const struct filemon *F, pid_t pid)
33049caa483SSimon J. Gerraty {
33149caa483SSimon J. Gerraty int ops, trpoints;
33249caa483SSimon J. Gerraty
33349caa483SSimon J. Gerraty ops = KTROP_SET|KTRFLAG_DESCEND;
33449caa483SSimon J. Gerraty trpoints = KTRFACv2;
33549caa483SSimon J. Gerraty trpoints |= KTRFAC_SYSCALL|KTRFAC_NAMEI|KTRFAC_SYSRET;
33649caa483SSimon J. Gerraty trpoints |= KTRFAC_INHERIT;
33749caa483SSimon J. Gerraty if (fktrace(F->ktrfd, ops, trpoints, pid) == -1)
33849caa483SSimon J. Gerraty return -1;
33949caa483SSimon J. Gerraty
34049caa483SSimon J. Gerraty return 0;
34149caa483SSimon J. Gerraty }
34249caa483SSimon J. Gerraty
34349caa483SSimon J. Gerraty /*
34449caa483SSimon J. Gerraty * filemon_close(F)
34549caa483SSimon J. Gerraty *
34649caa483SSimon J. Gerraty * Close F for output if necessary, and free a filemon descriptor.
34749caa483SSimon J. Gerraty * Returns 0 on success; sets errno and returns -1 on failure, but
34849caa483SSimon J. Gerraty * frees the filemon descriptor either way;
34949caa483SSimon J. Gerraty */
35049caa483SSimon J. Gerraty int
filemon_close(struct filemon * F)35149caa483SSimon J. Gerraty filemon_close(struct filemon *F)
35249caa483SSimon J. Gerraty {
35349caa483SSimon J. Gerraty struct filemon_state *S;
35449caa483SSimon J. Gerraty int error = 0;
35549caa483SSimon J. Gerraty
35649caa483SSimon J. Gerraty /* Close for output. */
35749caa483SSimon J. Gerraty if (filemon_closefd(F) == -1 && error == 0)
35849caa483SSimon J. Gerraty error = errno;
35949caa483SSimon J. Gerraty
36049caa483SSimon J. Gerraty /* Close the ktrace pipe. */
36149caa483SSimon J. Gerraty if (fclose(F->in) == EOF && error == 0)
36249caa483SSimon J. Gerraty error = errno;
36349caa483SSimon J. Gerraty if (close(F->ktrfd) == -1 && error == 0)
36449caa483SSimon J. Gerraty error = errno;
36549caa483SSimon J. Gerraty
36649caa483SSimon J. Gerraty /* Free any active records. */
36749caa483SSimon J. Gerraty while ((S = RB_TREE_MIN(&F->active)) != NULL) {
36849caa483SSimon J. Gerraty rb_tree_remove_node(&F->active, S);
36949caa483SSimon J. Gerraty free(S);
37049caa483SSimon J. Gerraty }
37149caa483SSimon J. Gerraty
37249caa483SSimon J. Gerraty /* Free the filemon descriptor. */
37349caa483SSimon J. Gerraty free(F);
37449caa483SSimon J. Gerraty
37549caa483SSimon J. Gerraty /* Set errno and return -1 if anything went wrong. */
37606b9b3e0SSimon J. Gerraty if (error != 0) {
37749caa483SSimon J. Gerraty errno = error;
37849caa483SSimon J. Gerraty return -1;
37949caa483SSimon J. Gerraty }
38049caa483SSimon J. Gerraty
38149caa483SSimon J. Gerraty /* Success! */
38249caa483SSimon J. Gerraty return 0;
38349caa483SSimon J. Gerraty }
38449caa483SSimon J. Gerraty
38549caa483SSimon J. Gerraty /*
38649caa483SSimon J. Gerraty * filemon_readfd(F)
38749caa483SSimon J. Gerraty *
38849caa483SSimon J. Gerraty * Returns a file descriptor which will select/poll ready for read
38949caa483SSimon J. Gerraty * when there are filemon events to be processed by
39049caa483SSimon J. Gerraty * filemon_process, or -1 if anything has gone wrong.
39149caa483SSimon J. Gerraty */
39249caa483SSimon J. Gerraty int
filemon_readfd(const struct filemon * F)39349caa483SSimon J. Gerraty filemon_readfd(const struct filemon *F)
39449caa483SSimon J. Gerraty {
39549caa483SSimon J. Gerraty
39649caa483SSimon J. Gerraty if (F->state == FILEMON_ERROR)
39749caa483SSimon J. Gerraty return -1;
39849caa483SSimon J. Gerraty return fileno(F->in);
39949caa483SSimon J. Gerraty }
40049caa483SSimon J. Gerraty
40149caa483SSimon J. Gerraty /*
40249caa483SSimon J. Gerraty * filemon_dispatch(F)
40349caa483SSimon J. Gerraty *
40449caa483SSimon J. Gerraty * Internal subroutine to dispatch a filemon ktrace event.
40549caa483SSimon J. Gerraty * Silently ignore events that we don't recognize.
40649caa483SSimon J. Gerraty */
40749caa483SSimon J. Gerraty static void
filemon_dispatch(struct filemon * F)40849caa483SSimon J. Gerraty filemon_dispatch(struct filemon *F)
40949caa483SSimon J. Gerraty {
41049caa483SSimon J. Gerraty const struct filemon_key key = {
41149caa483SSimon J. Gerraty .pid = F->hdr.ktr_pid,
41249caa483SSimon J. Gerraty .lid = F->hdr.ktr_lid,
41349caa483SSimon J. Gerraty };
41449caa483SSimon J. Gerraty struct filemon_state *S;
41549caa483SSimon J. Gerraty
41649caa483SSimon J. Gerraty switch (F->hdr.ktr_type) {
41749caa483SSimon J. Gerraty case KTR_SYSCALL: {
41849caa483SSimon J. Gerraty struct ktr_syscall *call = &F->payload.syscall;
41949caa483SSimon J. Gerraty struct filemon_state *S1;
42049caa483SSimon J. Gerraty
42149caa483SSimon J. Gerraty /* Validate the syscall code. */
42249caa483SSimon J. Gerraty if (call->ktr_code < 0 ||
42349caa483SSimon J. Gerraty (size_t)call->ktr_code >= __arraycount(filemon_syscalls) ||
42449caa483SSimon J. Gerraty filemon_syscalls[call->ktr_code] == NULL)
42549caa483SSimon J. Gerraty break;
42649caa483SSimon J. Gerraty
42749caa483SSimon J. Gerraty /*
42849caa483SSimon J. Gerraty * Invoke the syscall-specific logic to create a new
42949caa483SSimon J. Gerraty * active state.
43049caa483SSimon J. Gerraty */
43149caa483SSimon J. Gerraty S = (*filemon_syscalls[call->ktr_code])(F, &key, call);
43249caa483SSimon J. Gerraty if (S == NULL)
43349caa483SSimon J. Gerraty break;
43449caa483SSimon J. Gerraty
43549caa483SSimon J. Gerraty /*
43649caa483SSimon J. Gerraty * Insert the active state, or ignore it if there
43749caa483SSimon J. Gerraty * already is one.
43849caa483SSimon J. Gerraty *
43949caa483SSimon J. Gerraty * Collisions shouldn't happen because the states are
44049caa483SSimon J. Gerraty * keyed by <pid,lid>, in which syscalls should happen
44149caa483SSimon J. Gerraty * sequentially in CALL/RET pairs, but let's be
44249caa483SSimon J. Gerraty * defensive.
44349caa483SSimon J. Gerraty */
44449caa483SSimon J. Gerraty S1 = rb_tree_insert_node(&F->active, S);
44549caa483SSimon J. Gerraty if (S1 != S) {
44649caa483SSimon J. Gerraty /* XXX Which one to drop? */
44749caa483SSimon J. Gerraty free(S);
44849caa483SSimon J. Gerraty break;
44949caa483SSimon J. Gerraty }
45049caa483SSimon J. Gerraty break;
45149caa483SSimon J. Gerraty }
45249caa483SSimon J. Gerraty case KTR_NAMEI:
45349caa483SSimon J. Gerraty /* Find an active syscall state, or drop it. */
45449caa483SSimon J. Gerraty S = rb_tree_find_node(&F->active, &key);
45549caa483SSimon J. Gerraty if (S == NULL)
45649caa483SSimon J. Gerraty break;
45749caa483SSimon J. Gerraty /* Find the position of the next path, or drop it. */
45849caa483SSimon J. Gerraty if (S->i >= S->npath)
45949caa483SSimon J. Gerraty break;
46049caa483SSimon J. Gerraty /* Record the path. */
46149caa483SSimon J. Gerraty S->path[S->i++] = strndup(F->payload.namei,
46249caa483SSimon J. Gerraty sizeof F->payload.namei);
46349caa483SSimon J. Gerraty break;
46449caa483SSimon J. Gerraty case KTR_SYSRET: {
46549caa483SSimon J. Gerraty struct ktr_sysret *ret = &F->payload.sysret;
46649caa483SSimon J. Gerraty unsigned i;
46749caa483SSimon J. Gerraty
46849caa483SSimon J. Gerraty /* Find and remove an active syscall state, or drop it. */
46949caa483SSimon J. Gerraty S = rb_tree_find_node(&F->active, &key);
47049caa483SSimon J. Gerraty if (S == NULL)
47149caa483SSimon J. Gerraty break;
47249caa483SSimon J. Gerraty rb_tree_remove_node(&F->active, S);
47349caa483SSimon J. Gerraty
47449caa483SSimon J. Gerraty /*
47549caa483SSimon J. Gerraty * If the active syscall state matches this return,
47649caa483SSimon J. Gerraty * invoke the syscall-specific logic to show a filemon
47749caa483SSimon J. Gerraty * event.
47849caa483SSimon J. Gerraty */
47949caa483SSimon J. Gerraty /* XXX What to do if syscall code doesn't match? */
48049caa483SSimon J. Gerraty if (S->i == S->npath && S->syscode == ret->ktr_code)
481956e45f6SSimon J. Gerraty S->show(F, S, ret);
48249caa483SSimon J. Gerraty
48349caa483SSimon J. Gerraty /* Free the state now that it is no longer active. */
48449caa483SSimon J. Gerraty for (i = 0; i < S->i; i++)
48549caa483SSimon J. Gerraty free(S->path[i]);
48649caa483SSimon J. Gerraty free(S);
48749caa483SSimon J. Gerraty break;
48849caa483SSimon J. Gerraty }
48949caa483SSimon J. Gerraty default:
49049caa483SSimon J. Gerraty /* Ignore all other ktrace events. */
49149caa483SSimon J. Gerraty break;
49249caa483SSimon J. Gerraty }
49349caa483SSimon J. Gerraty }
49449caa483SSimon J. Gerraty
49549caa483SSimon J. Gerraty /*
49649caa483SSimon J. Gerraty * filemon_process(F)
49749caa483SSimon J. Gerraty *
49849caa483SSimon J. Gerraty * Process all pending events after filemon_readfd(F) has
49949caa483SSimon J. Gerraty * selected/polled ready for read.
50049caa483SSimon J. Gerraty *
50149caa483SSimon J. Gerraty * Returns -1 on failure, 0 on end of events, and anything else if
50249caa483SSimon J. Gerraty * there may be more events.
50349caa483SSimon J. Gerraty *
50449caa483SSimon J. Gerraty * XXX What about fairness to other activities in the event loop?
50549caa483SSimon J. Gerraty * If we stop while there's events buffered in F->in, then select
50649caa483SSimon J. Gerraty * or poll may not return ready even though there's work queued up
50749caa483SSimon J. Gerraty * in the buffer of F->in, but if we don't stop then ktrace events
50849caa483SSimon J. Gerraty * may overwhelm all other activity in the event loop.
50949caa483SSimon J. Gerraty */
51049caa483SSimon J. Gerraty int
filemon_process(struct filemon * F)51149caa483SSimon J. Gerraty filemon_process(struct filemon *F)
51249caa483SSimon J. Gerraty {
51349caa483SSimon J. Gerraty size_t nread;
51449caa483SSimon J. Gerraty
51549caa483SSimon J. Gerraty top: /* If the child has exited, nothing to do. */
51649caa483SSimon J. Gerraty /* XXX What if one thread calls exit while another is running? */
51749caa483SSimon J. Gerraty if (F->child == 0)
51849caa483SSimon J. Gerraty return 0;
51949caa483SSimon J. Gerraty
52049caa483SSimon J. Gerraty /* If we're waiting for input, read some. */
52106b9b3e0SSimon J. Gerraty if (F->resid > 0) {
52249caa483SSimon J. Gerraty nread = fread(F->p, 1, F->resid, F->in);
52349caa483SSimon J. Gerraty if (nread == 0) {
52406b9b3e0SSimon J. Gerraty if (feof(F->in) != 0)
52549caa483SSimon J. Gerraty return 0;
52606b9b3e0SSimon J. Gerraty assert(ferror(F->in) != 0);
52749caa483SSimon J. Gerraty /*
52849caa483SSimon J. Gerraty * If interrupted or would block, there may be
52949caa483SSimon J. Gerraty * more events. Otherwise fail.
53049caa483SSimon J. Gerraty */
53149caa483SSimon J. Gerraty if (errno == EAGAIN || errno == EINTR)
53249caa483SSimon J. Gerraty return 1;
53349caa483SSimon J. Gerraty F->state = FILEMON_ERROR;
53449caa483SSimon J. Gerraty F->p = NULL;
53549caa483SSimon J. Gerraty F->resid = 0;
53649caa483SSimon J. Gerraty return -1;
53749caa483SSimon J. Gerraty }
53849caa483SSimon J. Gerraty assert(nread <= F->resid);
53949caa483SSimon J. Gerraty F->p += nread;
54049caa483SSimon J. Gerraty F->resid -= nread;
54106b9b3e0SSimon J. Gerraty if (F->resid > 0) /* may be more events */
54249caa483SSimon J. Gerraty return 1;
54349caa483SSimon J. Gerraty }
54449caa483SSimon J. Gerraty
54549caa483SSimon J. Gerraty /* Process a state transition now that we've read a buffer. */
54649caa483SSimon J. Gerraty switch (F->state) {
54749caa483SSimon J. Gerraty case FILEMON_START: /* just started filemon; read header next */
54849caa483SSimon J. Gerraty F->state = FILEMON_HEADER;
54949caa483SSimon J. Gerraty F->p = (void *)&F->hdr;
55049caa483SSimon J. Gerraty F->resid = sizeof F->hdr;
55149caa483SSimon J. Gerraty goto top;
55249caa483SSimon J. Gerraty case FILEMON_HEADER: /* read header */
55349caa483SSimon J. Gerraty /* Sanity-check ktrace header; then read payload. */
55449caa483SSimon J. Gerraty if (F->hdr.ktr_len < 0 ||
55549caa483SSimon J. Gerraty (size_t)F->hdr.ktr_len > sizeof F->payload) {
55649caa483SSimon J. Gerraty F->state = FILEMON_ERROR;
55749caa483SSimon J. Gerraty F->p = NULL;
55849caa483SSimon J. Gerraty F->resid = 0;
55949caa483SSimon J. Gerraty errno = EIO;
56049caa483SSimon J. Gerraty return -1;
56149caa483SSimon J. Gerraty }
56249caa483SSimon J. Gerraty F->state = FILEMON_PAYLOAD;
56349caa483SSimon J. Gerraty F->p = (void *)&F->payload;
56449caa483SSimon J. Gerraty F->resid = (size_t)F->hdr.ktr_len;
56549caa483SSimon J. Gerraty goto top;
56649caa483SSimon J. Gerraty case FILEMON_PAYLOAD: /* read header and payload */
56749caa483SSimon J. Gerraty /* Dispatch ktrace event; then read next header. */
56849caa483SSimon J. Gerraty filemon_dispatch(F);
56949caa483SSimon J. Gerraty F->state = FILEMON_HEADER;
57049caa483SSimon J. Gerraty F->p = (void *)&F->hdr;
57149caa483SSimon J. Gerraty F->resid = sizeof F->hdr;
57249caa483SSimon J. Gerraty goto top;
57349caa483SSimon J. Gerraty default: /* paranoia */
57449caa483SSimon J. Gerraty F->state = FILEMON_ERROR;
57549caa483SSimon J. Gerraty /*FALLTHROUGH*/
57649caa483SSimon J. Gerraty case FILEMON_ERROR: /* persistent error indicator */
57749caa483SSimon J. Gerraty F->p = NULL;
57849caa483SSimon J. Gerraty F->resid = 0;
57949caa483SSimon J. Gerraty errno = EIO;
58049caa483SSimon J. Gerraty return -1;
58149caa483SSimon J. Gerraty }
58249caa483SSimon J. Gerraty }
58349caa483SSimon J. Gerraty
58449caa483SSimon J. Gerraty static struct filemon_state *
syscall_enter(const struct filemon_key * key,const struct ktr_syscall * call,unsigned npath,void (* show)(struct filemon *,const struct filemon_state *,const struct ktr_sysret *))58506b9b3e0SSimon J. Gerraty syscall_enter(
58649caa483SSimon J. Gerraty const struct filemon_key *key, const struct ktr_syscall *call,
58749caa483SSimon J. Gerraty unsigned npath,
58849caa483SSimon J. Gerraty void (*show)(struct filemon *, const struct filemon_state *,
58949caa483SSimon J. Gerraty const struct ktr_sysret *))
59049caa483SSimon J. Gerraty {
59149caa483SSimon J. Gerraty struct filemon_state *S;
59249caa483SSimon J. Gerraty unsigned i;
59349caa483SSimon J. Gerraty
59449caa483SSimon J. Gerraty S = calloc(1, offsetof(struct filemon_state, path[npath]));
59549caa483SSimon J. Gerraty if (S == NULL)
59649caa483SSimon J. Gerraty return NULL;
59749caa483SSimon J. Gerraty S->key = *key;
59849caa483SSimon J. Gerraty S->show = show;
59949caa483SSimon J. Gerraty S->syscode = call->ktr_code;
60049caa483SSimon J. Gerraty S->i = 0;
60149caa483SSimon J. Gerraty S->npath = npath;
60249caa483SSimon J. Gerraty for (i = 0; i < npath; i++)
60349caa483SSimon J. Gerraty S->path[i] = NULL; /* paranoia */
60449caa483SSimon J. Gerraty
60549caa483SSimon J. Gerraty return S;
60649caa483SSimon J. Gerraty }
60749caa483SSimon J. Gerraty
60849caa483SSimon J. Gerraty static void
show_paths(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret,const char * prefix)60949caa483SSimon J. Gerraty show_paths(struct filemon *F, const struct filemon_state *S,
61049caa483SSimon J. Gerraty const struct ktr_sysret *ret, const char *prefix)
61149caa483SSimon J. Gerraty {
61249caa483SSimon J. Gerraty unsigned i;
61349caa483SSimon J. Gerraty
61449caa483SSimon J. Gerraty /* Caller must ensure all paths have been specified. */
61549caa483SSimon J. Gerraty assert(S->i == S->npath);
61649caa483SSimon J. Gerraty
61749caa483SSimon J. Gerraty /*
61849caa483SSimon J. Gerraty * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
61949caa483SSimon J. Gerraty * we're not producing output.
62049caa483SSimon J. Gerraty */
62106b9b3e0SSimon J. Gerraty if (ret->ktr_error != 0 && ret->ktr_error != -2)
62249caa483SSimon J. Gerraty return;
62349caa483SSimon J. Gerraty if (F->out == NULL)
62449caa483SSimon J. Gerraty return;
62549caa483SSimon J. Gerraty
62649caa483SSimon J. Gerraty /*
62749caa483SSimon J. Gerraty * Print the prefix, pid, and paths -- with the paths quoted if
62849caa483SSimon J. Gerraty * there's more than one.
62949caa483SSimon J. Gerraty */
63049caa483SSimon J. Gerraty fprintf(F->out, "%s %jd", prefix, (intmax_t)S->key.pid);
63149caa483SSimon J. Gerraty for (i = 0; i < S->npath; i++) {
63249caa483SSimon J. Gerraty const char *q = S->npath > 1 ? "'" : "";
63349caa483SSimon J. Gerraty fprintf(F->out, " %s%s%s", q, S->path[i], q);
63449caa483SSimon J. Gerraty }
63549caa483SSimon J. Gerraty fprintf(F->out, "\n");
63649caa483SSimon J. Gerraty }
63749caa483SSimon J. Gerraty
63849caa483SSimon J. Gerraty static void
show_retval(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret,const char * prefix)63949caa483SSimon J. Gerraty show_retval(struct filemon *F, const struct filemon_state *S,
64049caa483SSimon J. Gerraty const struct ktr_sysret *ret, const char *prefix)
64149caa483SSimon J. Gerraty {
64249caa483SSimon J. Gerraty
64349caa483SSimon J. Gerraty /*
64449caa483SSimon J. Gerraty * Ignore it if it failed or yielded EJUSTRETURN (-2), or if
64549caa483SSimon J. Gerraty * we're not producing output.
64649caa483SSimon J. Gerraty */
64706b9b3e0SSimon J. Gerraty if (ret->ktr_error != 0 && ret->ktr_error != -2)
64849caa483SSimon J. Gerraty return;
64949caa483SSimon J. Gerraty if (F->out == NULL)
65049caa483SSimon J. Gerraty return;
65149caa483SSimon J. Gerraty
65249caa483SSimon J. Gerraty fprintf(F->out, "%s %jd %jd\n", prefix, (intmax_t)S->key.pid,
65349caa483SSimon J. Gerraty (intmax_t)ret->ktr_retval);
65449caa483SSimon J. Gerraty }
65549caa483SSimon J. Gerraty
65649caa483SSimon J. Gerraty static void
show_chdir(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)65749caa483SSimon J. Gerraty show_chdir(struct filemon *F, const struct filemon_state *S,
65849caa483SSimon J. Gerraty const struct ktr_sysret *ret)
65949caa483SSimon J. Gerraty {
66049caa483SSimon J. Gerraty show_paths(F, S, ret, "C");
66149caa483SSimon J. Gerraty }
66249caa483SSimon J. Gerraty
66349caa483SSimon J. Gerraty static void
show_execve(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)66449caa483SSimon J. Gerraty show_execve(struct filemon *F, const struct filemon_state *S,
66549caa483SSimon J. Gerraty const struct ktr_sysret *ret)
66649caa483SSimon J. Gerraty {
66706b9b3e0SSimon J. Gerraty show_paths(F, S, ret, "E");
66849caa483SSimon J. Gerraty }
66949caa483SSimon J. Gerraty
67049caa483SSimon J. Gerraty static void
show_fork(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)67149caa483SSimon J. Gerraty show_fork(struct filemon *F, const struct filemon_state *S,
67249caa483SSimon J. Gerraty const struct ktr_sysret *ret)
67349caa483SSimon J. Gerraty {
67449caa483SSimon J. Gerraty show_retval(F, S, ret, "F");
67549caa483SSimon J. Gerraty }
67649caa483SSimon J. Gerraty
67749caa483SSimon J. Gerraty static void
show_link(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)67849caa483SSimon J. Gerraty show_link(struct filemon *F, const struct filemon_state *S,
67949caa483SSimon J. Gerraty const struct ktr_sysret *ret)
68049caa483SSimon J. Gerraty {
68149caa483SSimon J. Gerraty show_paths(F, S, ret, "L"); /* XXX same as symlink */
68249caa483SSimon J. Gerraty }
68349caa483SSimon J. Gerraty
68449caa483SSimon J. Gerraty static void
show_open_read(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)68549caa483SSimon J. Gerraty show_open_read(struct filemon *F, const struct filemon_state *S,
68649caa483SSimon J. Gerraty const struct ktr_sysret *ret)
68749caa483SSimon J. Gerraty {
68849caa483SSimon J. Gerraty show_paths(F, S, ret, "R");
68949caa483SSimon J. Gerraty }
69049caa483SSimon J. Gerraty
69149caa483SSimon J. Gerraty static void
show_open_write(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)69249caa483SSimon J. Gerraty show_open_write(struct filemon *F, const struct filemon_state *S,
69349caa483SSimon J. Gerraty const struct ktr_sysret *ret)
69449caa483SSimon J. Gerraty {
69549caa483SSimon J. Gerraty show_paths(F, S, ret, "W");
69649caa483SSimon J. Gerraty }
69749caa483SSimon J. Gerraty
69849caa483SSimon J. Gerraty static void
show_open_readwrite(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)69949caa483SSimon J. Gerraty show_open_readwrite(struct filemon *F, const struct filemon_state *S,
70049caa483SSimon J. Gerraty const struct ktr_sysret *ret)
70149caa483SSimon J. Gerraty {
70249caa483SSimon J. Gerraty show_paths(F, S, ret, "R");
70349caa483SSimon J. Gerraty show_paths(F, S, ret, "W");
70449caa483SSimon J. Gerraty }
70549caa483SSimon J. Gerraty
70649caa483SSimon J. Gerraty static void
show_openat_read(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)70749caa483SSimon J. Gerraty show_openat_read(struct filemon *F, const struct filemon_state *S,
70849caa483SSimon J. Gerraty const struct ktr_sysret *ret)
70949caa483SSimon J. Gerraty {
71049caa483SSimon J. Gerraty if (S->path[0][0] != '/')
71149caa483SSimon J. Gerraty show_paths(F, S, ret, "A");
71249caa483SSimon J. Gerraty show_paths(F, S, ret, "R");
71349caa483SSimon J. Gerraty }
71449caa483SSimon J. Gerraty
71549caa483SSimon J. Gerraty static void
show_openat_write(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)71649caa483SSimon J. Gerraty show_openat_write(struct filemon *F, const struct filemon_state *S,
71749caa483SSimon J. Gerraty const struct ktr_sysret *ret)
71849caa483SSimon J. Gerraty {
71949caa483SSimon J. Gerraty if (S->path[0][0] != '/')
72049caa483SSimon J. Gerraty show_paths(F, S, ret, "A");
72149caa483SSimon J. Gerraty show_paths(F, S, ret, "W");
72249caa483SSimon J. Gerraty }
72349caa483SSimon J. Gerraty
72449caa483SSimon J. Gerraty static void
show_openat_readwrite(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)72549caa483SSimon J. Gerraty show_openat_readwrite(struct filemon *F, const struct filemon_state *S,
72649caa483SSimon J. Gerraty const struct ktr_sysret *ret)
72749caa483SSimon J. Gerraty {
72849caa483SSimon J. Gerraty if (S->path[0][0] != '/')
72949caa483SSimon J. Gerraty show_paths(F, S, ret, "A");
73049caa483SSimon J. Gerraty show_paths(F, S, ret, "R");
73149caa483SSimon J. Gerraty show_paths(F, S, ret, "W");
73249caa483SSimon J. Gerraty }
73349caa483SSimon J. Gerraty
73449caa483SSimon J. Gerraty static void
show_symlink(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)73549caa483SSimon J. Gerraty show_symlink(struct filemon *F, const struct filemon_state *S,
73649caa483SSimon J. Gerraty const struct ktr_sysret *ret)
73749caa483SSimon J. Gerraty {
73849caa483SSimon J. Gerraty show_paths(F, S, ret, "L"); /* XXX same as link */
73949caa483SSimon J. Gerraty }
74049caa483SSimon J. Gerraty
74149caa483SSimon J. Gerraty static void
show_unlink(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)74249caa483SSimon J. Gerraty show_unlink(struct filemon *F, const struct filemon_state *S,
74349caa483SSimon J. Gerraty const struct ktr_sysret *ret)
74449caa483SSimon J. Gerraty {
74549caa483SSimon J. Gerraty show_paths(F, S, ret, "D");
74649caa483SSimon J. Gerraty }
74749caa483SSimon J. Gerraty
74849caa483SSimon J. Gerraty static void
show_rename(struct filemon * F,const struct filemon_state * S,const struct ktr_sysret * ret)74949caa483SSimon J. Gerraty show_rename(struct filemon *F, const struct filemon_state *S,
75049caa483SSimon J. Gerraty const struct ktr_sysret *ret)
75149caa483SSimon J. Gerraty {
75249caa483SSimon J. Gerraty show_paths(F, S, ret, "M");
75349caa483SSimon J. Gerraty }
75449caa483SSimon J. Gerraty
75506b9b3e0SSimon J. Gerraty /*ARGSUSED*/
75649caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_chdir(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)75749caa483SSimon J. Gerraty filemon_sys_chdir(struct filemon *F, const struct filemon_key *key,
75849caa483SSimon J. Gerraty const struct ktr_syscall *call)
75949caa483SSimon J. Gerraty {
76006b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_chdir);
76149caa483SSimon J. Gerraty }
76249caa483SSimon J. Gerraty
763dba7b0efSSimon J. Gerraty /* TODO: monitor fchdir as well */
764dba7b0efSSimon J. Gerraty
76506b9b3e0SSimon J. Gerraty /*ARGSUSED*/
76649caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_execve(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)76749caa483SSimon J. Gerraty filemon_sys_execve(struct filemon *F, const struct filemon_key *key,
76849caa483SSimon J. Gerraty const struct ktr_syscall *call)
76949caa483SSimon J. Gerraty {
77006b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_execve);
77149caa483SSimon J. Gerraty }
77249caa483SSimon J. Gerraty
77349caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_exit(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)77449caa483SSimon J. Gerraty filemon_sys_exit(struct filemon *F, const struct filemon_key *key,
77549caa483SSimon J. Gerraty const struct ktr_syscall *call)
77649caa483SSimon J. Gerraty {
77749caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1];
778956e45f6SSimon J. Gerraty int status = (int)args[0];
77949caa483SSimon J. Gerraty
78006b9b3e0SSimon J. Gerraty if (F->out != NULL) {
78149caa483SSimon J. Gerraty fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status);
78249caa483SSimon J. Gerraty if (key->pid == F->child) {
78349caa483SSimon J. Gerraty fprintf(F->out, "# Bye bye\n");
78449caa483SSimon J. Gerraty F->child = 0;
78549caa483SSimon J. Gerraty }
78649caa483SSimon J. Gerraty }
78749caa483SSimon J. Gerraty return NULL;
78849caa483SSimon J. Gerraty }
78949caa483SSimon J. Gerraty
79006b9b3e0SSimon J. Gerraty /*ARGSUSED*/
79149caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_fork(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)79249caa483SSimon J. Gerraty filemon_sys_fork(struct filemon *F, const struct filemon_key *key,
79349caa483SSimon J. Gerraty const struct ktr_syscall *call)
79449caa483SSimon J. Gerraty {
79506b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 0, &show_fork);
79649caa483SSimon J. Gerraty }
79749caa483SSimon J. Gerraty
79806b9b3e0SSimon J. Gerraty /*ARGSUSED*/
79949caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_link(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)80049caa483SSimon J. Gerraty filemon_sys_link(struct filemon *F, const struct filemon_key *key,
80149caa483SSimon J. Gerraty const struct ktr_syscall *call)
80249caa483SSimon J. Gerraty {
80306b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 2, &show_link);
80449caa483SSimon J. Gerraty }
80549caa483SSimon J. Gerraty
80606b9b3e0SSimon J. Gerraty /*ARGSUSED*/
80749caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_open(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)80849caa483SSimon J. Gerraty filemon_sys_open(struct filemon *F, const struct filemon_key *key,
80949caa483SSimon J. Gerraty const struct ktr_syscall *call)
81049caa483SSimon J. Gerraty {
81149caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1];
81249caa483SSimon J. Gerraty int flags;
81349caa483SSimon J. Gerraty
81449caa483SSimon J. Gerraty if (call->ktr_argsize < 2)
81549caa483SSimon J. Gerraty return NULL;
816956e45f6SSimon J. Gerraty flags = (int)args[1];
81749caa483SSimon J. Gerraty
81849caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR)
81906b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_open_readwrite);
82049caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY)
82106b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_open_write);
82249caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY)
82306b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_open_read);
82449caa483SSimon J. Gerraty else
82549caa483SSimon J. Gerraty return NULL; /* XXX Do we care if no read or write? */
82649caa483SSimon J. Gerraty }
82749caa483SSimon J. Gerraty
82806b9b3e0SSimon J. Gerraty /*ARGSUSED*/
82949caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_openat(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)83049caa483SSimon J. Gerraty filemon_sys_openat(struct filemon *F, const struct filemon_key *key,
83149caa483SSimon J. Gerraty const struct ktr_syscall *call)
83249caa483SSimon J. Gerraty {
83349caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1];
83449caa483SSimon J. Gerraty int flags, fd;
83549caa483SSimon J. Gerraty
836dba7b0efSSimon J. Gerraty /*
837dba7b0efSSimon J. Gerraty * XXX: In the .meta log, the base directory is missing, which makes
838dba7b0efSSimon J. Gerraty * all references to relative pathnames useless.
839dba7b0efSSimon J. Gerraty */
840dba7b0efSSimon J. Gerraty
84149caa483SSimon J. Gerraty if (call->ktr_argsize < 3)
84249caa483SSimon J. Gerraty return NULL;
843956e45f6SSimon J. Gerraty fd = (int)args[0];
844956e45f6SSimon J. Gerraty flags = (int)args[2];
84549caa483SSimon J. Gerraty
84649caa483SSimon J. Gerraty if (fd == AT_CWD) {
84749caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR)
84806b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1,
84949caa483SSimon J. Gerraty &show_open_readwrite);
85049caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY)
85106b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_open_write);
85249caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY)
85306b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_open_read);
85449caa483SSimon J. Gerraty else
85549caa483SSimon J. Gerraty return NULL;
85649caa483SSimon J. Gerraty } else {
85749caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR)
85806b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1,
85949caa483SSimon J. Gerraty &show_openat_readwrite);
86049caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY)
86106b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_openat_write);
86249caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY)
86306b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_openat_read);
86449caa483SSimon J. Gerraty else
86549caa483SSimon J. Gerraty return NULL;
86649caa483SSimon J. Gerraty }
86749caa483SSimon J. Gerraty }
86849caa483SSimon J. Gerraty
869dba7b0efSSimon J. Gerraty /* TODO: monitor the other *at syscalls as well, not only openat. */
870dba7b0efSSimon J. Gerraty
87106b9b3e0SSimon J. Gerraty /*ARGSUSED*/
87249caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_symlink(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)87349caa483SSimon J. Gerraty filemon_sys_symlink(struct filemon *F, const struct filemon_key *key,
87449caa483SSimon J. Gerraty const struct ktr_syscall *call)
87549caa483SSimon J. Gerraty {
87606b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 2, &show_symlink);
87749caa483SSimon J. Gerraty }
87849caa483SSimon J. Gerraty
87906b9b3e0SSimon J. Gerraty /*ARGSUSED*/
88049caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_unlink(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)88149caa483SSimon J. Gerraty filemon_sys_unlink(struct filemon *F, const struct filemon_key *key,
88249caa483SSimon J. Gerraty const struct ktr_syscall *call)
88349caa483SSimon J. Gerraty {
88406b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 1, &show_unlink);
88549caa483SSimon J. Gerraty }
88649caa483SSimon J. Gerraty
88706b9b3e0SSimon J. Gerraty /*ARGSUSED*/
88849caa483SSimon J. Gerraty static struct filemon_state *
filemon_sys_rename(struct filemon * F,const struct filemon_key * key,const struct ktr_syscall * call)88949caa483SSimon J. Gerraty filemon_sys_rename(struct filemon *F, const struct filemon_key *key,
89049caa483SSimon J. Gerraty const struct ktr_syscall *call)
89149caa483SSimon J. Gerraty {
89206b9b3e0SSimon J. Gerraty return syscall_enter(key, call, 2, &show_rename);
89349caa483SSimon J. Gerraty }
894