1*e2eeea75SSimon J. Gerraty /* $NetBSD: filemon_ktrace.c,v 1.4 2020/11/05 17:27:16 rillig Exp $ */ 249caa483SSimon J. Gerraty 349caa483SSimon 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 13349caa483SSimon J. Gerraty static int 13449caa483SSimon J. Gerraty compare_filemon_states(void *cookie, const void *na, const void *nb) 13549caa483SSimon J. Gerraty { 13649caa483SSimon J. Gerraty const struct filemon_state *Sa = na; 13749caa483SSimon J. Gerraty const struct filemon_state *Sb = nb; 13849caa483SSimon J. Gerraty 13949caa483SSimon J. Gerraty if (Sa->key.pid < Sb->key.pid) 14049caa483SSimon J. Gerraty return -1; 14149caa483SSimon J. Gerraty if (Sa->key.pid > Sb->key.pid) 14249caa483SSimon J. Gerraty return +1; 14349caa483SSimon J. Gerraty if (Sa->key.lid < Sb->key.lid) 14449caa483SSimon J. Gerraty return -1; 14549caa483SSimon J. Gerraty if (Sa->key.lid > Sb->key.lid) 14649caa483SSimon J. Gerraty return +1; 14749caa483SSimon J. Gerraty return 0; 14849caa483SSimon J. Gerraty } 14949caa483SSimon J. Gerraty 15049caa483SSimon J. Gerraty static int 15149caa483SSimon J. Gerraty compare_filemon_key(void *cookie, const void *n, const void *k) 15249caa483SSimon J. Gerraty { 15349caa483SSimon J. Gerraty const struct filemon_state *S = n; 15449caa483SSimon J. Gerraty const struct filemon_key *key = k; 15549caa483SSimon J. Gerraty 15649caa483SSimon J. Gerraty if (S->key.pid < key->pid) 15749caa483SSimon J. Gerraty return -1; 15849caa483SSimon J. Gerraty if (S->key.pid > key->pid) 15949caa483SSimon J. Gerraty return +1; 16049caa483SSimon J. Gerraty if (S->key.lid < key->lid) 16149caa483SSimon J. Gerraty return -1; 16249caa483SSimon J. Gerraty if (S->key.lid > key->lid) 16349caa483SSimon J. Gerraty return +1; 16449caa483SSimon J. Gerraty return 0; 16549caa483SSimon J. Gerraty } 16649caa483SSimon J. Gerraty 16749caa483SSimon J. Gerraty static const rb_tree_ops_t filemon_rb_ops = { 16849caa483SSimon J. Gerraty .rbto_compare_nodes = &compare_filemon_states, 16949caa483SSimon J. Gerraty .rbto_compare_key = &compare_filemon_key, 17049caa483SSimon J. Gerraty .rbto_node_offset = offsetof(struct filemon_state, node), 17149caa483SSimon J. Gerraty .rbto_context = NULL, 17249caa483SSimon J. Gerraty }; 17349caa483SSimon J. Gerraty 17449caa483SSimon J. Gerraty /* 17549caa483SSimon J. Gerraty * filemon_path() 17649caa483SSimon J. Gerraty * 17749caa483SSimon J. Gerraty * Return a pointer to a constant string denoting the `path' of 17849caa483SSimon J. Gerraty * the filemon. 17949caa483SSimon J. Gerraty */ 18049caa483SSimon J. Gerraty const char * 18149caa483SSimon J. Gerraty filemon_path(void) 18249caa483SSimon J. Gerraty { 18349caa483SSimon J. Gerraty 18449caa483SSimon J. Gerraty return "ktrace"; 18549caa483SSimon J. Gerraty } 18649caa483SSimon J. Gerraty 18749caa483SSimon J. Gerraty /* 18849caa483SSimon J. Gerraty * filemon_open() 18949caa483SSimon J. Gerraty * 19049caa483SSimon J. Gerraty * Allocate a filemon descriptor. Returns NULL and sets errno on 19149caa483SSimon J. Gerraty * failure. 19249caa483SSimon J. Gerraty */ 19349caa483SSimon J. Gerraty struct filemon * 19449caa483SSimon J. Gerraty filemon_open(void) 19549caa483SSimon J. Gerraty { 19649caa483SSimon J. Gerraty struct filemon *F; 19749caa483SSimon J. Gerraty int ktrpipe[2]; 19849caa483SSimon J. Gerraty int error; 19949caa483SSimon J. Gerraty 20049caa483SSimon J. Gerraty /* Allocate and zero a struct filemon object. */ 201*e2eeea75SSimon J. Gerraty F = calloc(1, sizeof *F); 20249caa483SSimon J. Gerraty if (F == NULL) 20349caa483SSimon J. Gerraty return NULL; 20449caa483SSimon J. Gerraty 20549caa483SSimon J. Gerraty /* Create a pipe for ktrace events. */ 20649caa483SSimon J. Gerraty if (pipe2(ktrpipe, O_CLOEXEC|O_NONBLOCK) == -1) { 20749caa483SSimon J. Gerraty error = errno; 20849caa483SSimon J. Gerraty goto fail0; 20949caa483SSimon J. Gerraty } 21049caa483SSimon J. Gerraty 21149caa483SSimon J. Gerraty /* Create a file stream for reading the ktrace events. */ 21249caa483SSimon J. Gerraty if ((F->in = fdopen(ktrpipe[0], "r")) == NULL) { 21349caa483SSimon J. Gerraty error = errno; 21449caa483SSimon J. Gerraty goto fail1; 21549caa483SSimon J. Gerraty } 21649caa483SSimon J. Gerraty ktrpipe[0] = -1; /* claimed by fdopen */ 21749caa483SSimon J. Gerraty 21849caa483SSimon J. Gerraty /* 21949caa483SSimon J. Gerraty * Set the fd for writing ktrace events and initialize the 22049caa483SSimon J. Gerraty * rbtree. The rest can be safely initialized to zero. 22149caa483SSimon J. Gerraty */ 22249caa483SSimon J. Gerraty F->ktrfd = ktrpipe[1]; 22349caa483SSimon J. Gerraty rb_tree_init(&F->active, &filemon_rb_ops); 22449caa483SSimon J. Gerraty 22549caa483SSimon J. Gerraty /* Success! */ 22649caa483SSimon J. Gerraty return F; 22749caa483SSimon J. Gerraty 22849caa483SSimon J. Gerraty fail2: __unused 22949caa483SSimon J. Gerraty (void)fclose(F->in); 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 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. */ 26549caa483SSimon J. Gerraty if (error) { 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 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 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 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 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. */ 37649caa483SSimon J. Gerraty if (error) { 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 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 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 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. */ 52149caa483SSimon J. Gerraty if (F->resid) { 52249caa483SSimon J. Gerraty nread = fread(F->p, 1, F->resid, F->in); 52349caa483SSimon J. Gerraty if (nread == 0) { 52449caa483SSimon J. Gerraty if (feof(F->in)) 52549caa483SSimon J. Gerraty return 0; 52649caa483SSimon J. Gerraty assert(ferror(F->in)); 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; 54149caa483SSimon J. Gerraty if (F->resid) /* 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 * 58549caa483SSimon J. Gerraty syscall_enter(struct filemon *F, 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 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 */ 62149caa483SSimon J. Gerraty if (ret->ktr_error && 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 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 */ 64749caa483SSimon J. Gerraty if (ret->ktr_error && 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 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 66449caa483SSimon J. Gerraty show_execve(struct filemon *F, const struct filemon_state *S, 66549caa483SSimon J. Gerraty const struct ktr_sysret *ret) 66649caa483SSimon J. Gerraty { 66749caa483SSimon J. Gerraty return show_paths(F, S, ret, "E"); 66849caa483SSimon J. Gerraty } 66949caa483SSimon J. Gerraty 67049caa483SSimon J. Gerraty static void 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 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 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 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 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 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 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 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 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 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 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 75549caa483SSimon J. Gerraty static struct filemon_state * 75649caa483SSimon J. Gerraty filemon_sys_chdir(struct filemon *F, const struct filemon_key *key, 75749caa483SSimon J. Gerraty const struct ktr_syscall *call) 75849caa483SSimon J. Gerraty { 75949caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_chdir); 76049caa483SSimon J. Gerraty } 76149caa483SSimon J. Gerraty 76249caa483SSimon J. Gerraty static struct filemon_state * 76349caa483SSimon J. Gerraty filemon_sys_execve(struct filemon *F, const struct filemon_key *key, 76449caa483SSimon J. Gerraty const struct ktr_syscall *call) 76549caa483SSimon J. Gerraty { 76649caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_execve); 76749caa483SSimon J. Gerraty } 76849caa483SSimon J. Gerraty 76949caa483SSimon J. Gerraty static struct filemon_state * 77049caa483SSimon J. Gerraty filemon_sys_exit(struct filemon *F, const struct filemon_key *key, 77149caa483SSimon J. Gerraty const struct ktr_syscall *call) 77249caa483SSimon J. Gerraty { 77349caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1]; 774956e45f6SSimon J. Gerraty int status = (int)args[0]; 77549caa483SSimon J. Gerraty 77649caa483SSimon J. Gerraty if (F->out) { 77749caa483SSimon J. Gerraty fprintf(F->out, "X %jd %d\n", (intmax_t)key->pid, status); 77849caa483SSimon J. Gerraty if (key->pid == F->child) { 77949caa483SSimon J. Gerraty fprintf(F->out, "# Bye bye\n"); 78049caa483SSimon J. Gerraty F->child = 0; 78149caa483SSimon J. Gerraty } 78249caa483SSimon J. Gerraty } 78349caa483SSimon J. Gerraty return NULL; 78449caa483SSimon J. Gerraty } 78549caa483SSimon J. Gerraty 78649caa483SSimon J. Gerraty static struct filemon_state * 78749caa483SSimon J. Gerraty filemon_sys_fork(struct filemon *F, const struct filemon_key *key, 78849caa483SSimon J. Gerraty const struct ktr_syscall *call) 78949caa483SSimon J. Gerraty { 79049caa483SSimon J. Gerraty return syscall_enter(F, key, call, 0, &show_fork); 79149caa483SSimon J. Gerraty } 79249caa483SSimon J. Gerraty 79349caa483SSimon J. Gerraty static struct filemon_state * 79449caa483SSimon J. Gerraty filemon_sys_link(struct filemon *F, const struct filemon_key *key, 79549caa483SSimon J. Gerraty const struct ktr_syscall *call) 79649caa483SSimon J. Gerraty { 79749caa483SSimon J. Gerraty return syscall_enter(F, key, call, 2, &show_link); 79849caa483SSimon J. Gerraty } 79949caa483SSimon J. Gerraty 80049caa483SSimon J. Gerraty static struct filemon_state * 80149caa483SSimon J. Gerraty filemon_sys_open(struct filemon *F, const struct filemon_key *key, 80249caa483SSimon J. Gerraty const struct ktr_syscall *call) 80349caa483SSimon J. Gerraty { 80449caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1]; 80549caa483SSimon J. Gerraty int flags; 80649caa483SSimon J. Gerraty 80749caa483SSimon J. Gerraty if (call->ktr_argsize < 2) 80849caa483SSimon J. Gerraty return NULL; 809956e45f6SSimon J. Gerraty flags = (int)args[1]; 81049caa483SSimon J. Gerraty 81149caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR) 81249caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_open_readwrite); 81349caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY) 81449caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_open_write); 81549caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY) 81649caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_open_read); 81749caa483SSimon J. Gerraty else 81849caa483SSimon J. Gerraty return NULL; /* XXX Do we care if no read or write? */ 81949caa483SSimon J. Gerraty } 82049caa483SSimon J. Gerraty 82149caa483SSimon J. Gerraty static struct filemon_state * 82249caa483SSimon J. Gerraty filemon_sys_openat(struct filemon *F, const struct filemon_key *key, 82349caa483SSimon J. Gerraty const struct ktr_syscall *call) 82449caa483SSimon J. Gerraty { 82549caa483SSimon J. Gerraty const register_t *args = (const void *)&call[1]; 82649caa483SSimon J. Gerraty int flags, fd; 82749caa483SSimon J. Gerraty 82849caa483SSimon J. Gerraty if (call->ktr_argsize < 3) 82949caa483SSimon J. Gerraty return NULL; 830956e45f6SSimon J. Gerraty fd = (int)args[0]; 831956e45f6SSimon J. Gerraty flags = (int)args[2]; 83249caa483SSimon J. Gerraty 83349caa483SSimon J. Gerraty if (fd == AT_CWD) { 83449caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR) 83549caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, 83649caa483SSimon J. Gerraty &show_open_readwrite); 83749caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY) 83849caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, 83949caa483SSimon J. Gerraty &show_open_write); 84049caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY) 84149caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_open_read); 84249caa483SSimon J. Gerraty else 84349caa483SSimon J. Gerraty return NULL; 84449caa483SSimon J. Gerraty } else { 84549caa483SSimon J. Gerraty if ((flags & O_RDWR) == O_RDWR) 84649caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, 84749caa483SSimon J. Gerraty &show_openat_readwrite); 84849caa483SSimon J. Gerraty else if ((flags & O_WRONLY) == O_WRONLY) 84949caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, 85049caa483SSimon J. Gerraty &show_openat_write); 85149caa483SSimon J. Gerraty else if ((flags & O_RDONLY) == O_RDONLY) 85249caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, 85349caa483SSimon J. Gerraty &show_openat_read); 85449caa483SSimon J. Gerraty else 85549caa483SSimon J. Gerraty return NULL; 85649caa483SSimon J. Gerraty } 85749caa483SSimon J. Gerraty } 85849caa483SSimon J. Gerraty 85949caa483SSimon J. Gerraty static struct filemon_state * 86049caa483SSimon J. Gerraty filemon_sys_symlink(struct filemon *F, const struct filemon_key *key, 86149caa483SSimon J. Gerraty const struct ktr_syscall *call) 86249caa483SSimon J. Gerraty { 86349caa483SSimon J. Gerraty return syscall_enter(F, key, call, 2, &show_symlink); 86449caa483SSimon J. Gerraty } 86549caa483SSimon J. Gerraty 86649caa483SSimon J. Gerraty static struct filemon_state * 86749caa483SSimon J. Gerraty filemon_sys_unlink(struct filemon *F, const struct filemon_key *key, 86849caa483SSimon J. Gerraty const struct ktr_syscall *call) 86949caa483SSimon J. Gerraty { 87049caa483SSimon J. Gerraty return syscall_enter(F, key, call, 1, &show_unlink); 87149caa483SSimon J. Gerraty } 87249caa483SSimon J. Gerraty 87349caa483SSimon J. Gerraty static struct filemon_state * 87449caa483SSimon J. Gerraty filemon_sys_rename(struct filemon *F, const struct filemon_key *key, 87549caa483SSimon J. Gerraty const struct ktr_syscall *call) 87649caa483SSimon J. Gerraty { 87749caa483SSimon J. Gerraty return syscall_enter(F, key, call, 2, &show_rename); 87849caa483SSimon J. Gerraty } 879