From owner-svn-src-all@FreeBSD.ORG Mon Jun 4 22:54:20 2012 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 28BB21065672; Mon, 4 Jun 2012 22:54:20 +0000 (UTC) (envelope-from obrien@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 113518FC08; Mon, 4 Jun 2012 22:54:20 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q54MsKY0072826; Mon, 4 Jun 2012 22:54:20 GMT (envelope-from obrien@svn.freebsd.org) Received: (from obrien@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q54MsJjn072820; Mon, 4 Jun 2012 22:54:19 GMT (envelope-from obrien@svn.freebsd.org) Message-Id: <201206042254.q54MsJjn072820@svn.freebsd.org> From: "David E. O'Brien" Date: Mon, 4 Jun 2012 22:54:19 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r236592 - in head/sys: dev/filemon modules modules/filemon X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Jun 2012 22:54:20 -0000 Author: obrien Date: Mon Jun 4 22:54:19 2012 New Revision: 236592 URL: http://svn.freebsd.org/changeset/base/236592 Log: Add the 'filemon' device. 'filemon' is a kernel module that provides a device interface for processes to record system calls of its children. Submitted by: Juniper Networks. Added: head/sys/dev/filemon/ head/sys/dev/filemon/filemon.c (contents, props changed) head/sys/dev/filemon/filemon.h (contents, props changed) head/sys/dev/filemon/filemon_lock.c (contents, props changed) head/sys/dev/filemon/filemon_wrapper.c (contents, props changed) head/sys/modules/filemon/ head/sys/modules/filemon/Makefile (contents, props changed) Modified: head/sys/modules/Makefile Added: head/sys/dev/filemon/filemon.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/filemon/filemon.c Mon Jun 4 22:54:19 2012 (r236592) @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 2011, David E. O'Brien. + * Copyright (c) 2009-2011, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __FreeBSD_version >= 900041 +#include +#endif + +#include "filemon.h" + +#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) +#include +#include + +extern struct sysentvec ia32_freebsd_sysvec; +#endif + +extern struct sysentvec elf32_freebsd_sysvec; +extern struct sysentvec elf64_freebsd_sysvec; + +static d_close_t filemon_close; +static d_ioctl_t filemon_ioctl; +static d_open_t filemon_open; +static int filemon_unload(void); +static void filemon_load(void *); + +static struct cdevsw filemon_cdevsw = { + .d_version = D_VERSION, + .d_close = filemon_close, + .d_ioctl = filemon_ioctl, + .d_open = filemon_open, + .d_name = "filemon", +}; + +MALLOC_DECLARE(M_FILEMON); +MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor"); + +struct filemon { + TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */ + struct mtx mtx; /* Lock mutex for this filemon. */ + struct cv cv; /* Lock condition variable for this + filemon. */ + struct file *fp; /* Output file pointer. */ + struct thread *locker; /* Ptr to the thread locking this + filemon. */ + pid_t pid; /* The process ID being monitored. */ + char fname1[MAXPATHLEN]; /* Temporary filename buffer. */ + char fname2[MAXPATHLEN]; /* Temporary filename buffer. */ + char msgbufr[1024]; /* Output message buffer. */ +}; + +static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse); +static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free); +static int n_readers = 0; +static struct mtx access_mtx; +static struct cv access_cv; +static struct thread *access_owner = NULL; +static struct thread *access_requester = NULL; + +#if __FreeBSD_version < 701000 +static struct clonedevs *filemon_clones; +static eventhandler_tag eh_tag; +#else +static struct cdev *filemon_dev; +#endif + +#include "filemon_lock.c" +#include "filemon_wrapper.c" + +#if __FreeBSD_version < 701000 +static void +filemon_clone(void *arg, struct ucred *cred, char *name, int namelen, + struct cdev **dev) +{ + int u = -1; + size_t len; + + if (*dev != NULL) + return; + + len = strlen(name); + + if (len != 7) + return; + + if (bcmp(name,"filemon", 7) != 0) + return; + + /* Clone the device to the new minor number. */ + if (clone_create(&filemon_clones, &filemon_cdevsw, &u, dev, 0) != 0) + /* Create the /dev/filemonNN entry. */ + *dev = make_dev_cred(&filemon_cdevsw, u, cred, UID_ROOT, + GID_WHEEL, 0666, "filemon%d", u); + if (*dev != NULL) { + dev_ref(*dev); + (*dev)->si_flags |= SI_CHEAPCLONE; + } +} +#endif + +static void +filemon_dtr(void *data) +{ + struct filemon *filemon = data; + + if (filemon != NULL) { + struct file *fp = filemon->fp; + + /* Get exclusive write access. */ + filemon_lock_write(); + + /* Remove from the in-use list. */ + TAILQ_REMOVE(&filemons_inuse, filemon, link); + + filemon->fp = NULL; + filemon->pid = -1; + + /* Add to the free list. */ + TAILQ_INSERT_TAIL(&filemons_free, filemon, link); + + /* Give up write access. */ + filemon_unlock_write(); + + if (fp != NULL) + fdrop(fp, curthread); + } +} + +static int +filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, + struct thread *td) +{ + int error = 0; + struct filemon *filemon; + +#if __FreeBSD_version < 701000 + filemon = dev->si_drv1; +#else + devfs_get_cdevpriv((void **) &filemon); +#endif + + switch (cmd) { + /* Set the output file descriptor. */ + case FILEMON_SET_FD: +#if __FreeBSD_version < 900041 +#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), (a3)) +#else +#define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), CAP_WRITE | CAP_SEEK, (a3)) +#endif + if ((error = FGET_WRITE(td, *(int *)data, &filemon->fp)) == 0) + /* Write the file header. */ + filemon_comment(filemon); + break; + + /* Set the monitored process ID. */ + case FILEMON_SET_PID: + filemon->pid = *((pid_t *) data); + break; + + default: + error = EINVAL; + break; + } + + return (error); +} + +static int +filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused, + struct thread *td __unused) +{ + struct filemon *filemon; + + /* Get exclusive write access. */ + filemon_lock_write(); + + if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) + TAILQ_REMOVE(&filemons_free, filemon, link); + + /* Give up write access. */ + filemon_unlock_write(); + + if (filemon == NULL) { + filemon = malloc(sizeof(struct filemon), M_FILEMON, + M_WAITOK | M_ZERO); + + filemon->fp = NULL; + + mtx_init(&filemon->mtx, "filemon", "filemon", MTX_DEF); + cv_init(&filemon->cv, "filemon"); + } + + filemon->pid = curproc->p_pid; + +#if __FreeBSD_version < 701000 + dev->si_drv1 = filemon; +#else + devfs_set_cdevpriv(filemon, filemon_dtr); +#endif + + /* Get exclusive write access. */ + filemon_lock_write(); + + /* Add to the in-use list. */ + TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link); + + /* Give up write access. */ + filemon_unlock_write(); + + return (0); +} + +static int +filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused, + struct thread *td __unused) +{ +#if __FreeBSD_version < 701000 + filemon_dtr(dev->si_drv1); + + dev->si_drv1 = NULL; + + /* Schedule this cloned device to be destroyed. */ + destroy_dev_sched(dev); +#endif + + return (0); +} + +static void +filemon_load(void *dummy __unused) +{ + mtx_init(&access_mtx, "filemon", "filemon", MTX_DEF); + cv_init(&access_cv, "filemon"); + + /* Install the syscall wrappers. */ + filemon_wrapper_install(); + +#if __FreeBSD_version < 701000 + /* Enable device cloning. */ + clone_setup(&filemon_clones); + + /* Setup device cloning events. */ + eh_tag = EVENTHANDLER_REGISTER(dev_clone, filemon_clone, 0, 1000); +#else + filemon_dev = make_dev(&filemon_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, + "filemon"); +#endif +} + +static int +filemon_unload(void) +{ + struct filemon *filemon; + int error = 0; + + /* Get exclusive write access. */ + filemon_lock_write(); + + if (TAILQ_FIRST(&filemons_inuse) != NULL) + error = EBUSY; + else { +#if __FreeBSD_version >= 701000 + destroy_dev(filemon_dev); +#endif + + /* Deinstall the syscall wrappers. */ + filemon_wrapper_deinstall(); + } + + /* Give up write access. */ + filemon_unlock_write(); + + if (error == 0) { +#if __FreeBSD_version < 701000 + /* + * Check if there is still an event handler callback registered. + */ + if (eh_tag != 0) { + /* De-register the device cloning event handler. */ + EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); + eh_tag = 0; + + /* Stop device cloning. */ + clone_cleanup(&filemon_clones); + } +#endif + /* free() filemon structs free list. */ + filemon_lock_write(); + while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) { + TAILQ_REMOVE(&filemons_free, filemon, link); + mtx_destroy(&filemon->mtx); + cv_destroy(&filemon->cv); + free(filemon, M_FILEMON); + } + filemon_unlock_write(); + + mtx_destroy(&access_mtx); + cv_destroy(&access_cv); + } + + return (error); +} + +static int +filemon_modevent(module_t mod __unused, int type, void *data) +{ + int error = 0; + + switch (type) { + case MOD_LOAD: + filemon_load(data); + break; + + case MOD_UNLOAD: + error = filemon_unload(); + break; + + case MOD_SHUTDOWN: + break; + + default: + error = EOPNOTSUPP; + break; + + } + + return (error); +} + +DEV_MODULE(filemon, filemon_modevent, NULL); +MODULE_VERSION(filemon, 1); Added: head/sys/dev/filemon/filemon.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/filemon/filemon.h Mon Jun 4 22:54:19 2012 (r236592) @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2011, David E. O'Brien. + * Copyright (c) 2009-2011, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define FILEMON_SET_FD _IOWR('S', 1, int) +#define FILEMON_SET_PID _IOWR('S', 2, pid_t) + +#define FILEMON_VERSION 4 /* output format + (bump when adding record types) */ Added: head/sys/dev/filemon/filemon_lock.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/filemon/filemon_lock.c Mon Jun 4 22:54:19 2012 (r236592) @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2009-2011, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +static void +filemon_filemon_lock(struct filemon *filemon) +{ + mtx_lock(&filemon->mtx); + + while (filemon->locker != NULL && filemon->locker != curthread) + cv_wait(&filemon->cv, &filemon->mtx); + + filemon->locker = curthread; + + mtx_unlock(&filemon->mtx); +} + +static void +filemon_filemon_unlock(struct filemon *filemon) +{ + mtx_lock(&filemon->mtx); + + if (filemon->locker == curthread) + filemon->locker = NULL; + + /* Wake up threads waiting. */ + cv_broadcast(&filemon->cv); + + mtx_unlock(&filemon->mtx); +} + +static void +filemon_lock_read(void) +{ + mtx_lock(&access_mtx); + + while (access_owner != NULL || access_requester != NULL) + cv_wait(&access_cv, &access_mtx); + + n_readers++; + + /* Wake up threads waiting. */ + cv_broadcast(&access_cv); + + mtx_unlock(&access_mtx); +} + +static void +filemon_unlock_read(void) +{ + mtx_lock(&access_mtx); + + if (n_readers > 0) + n_readers--; + + /* Wake up a thread waiting. */ + cv_broadcast(&access_cv); + + mtx_unlock(&access_mtx); +} + +static void +filemon_lock_write(void) +{ + mtx_lock(&access_mtx); + + while (access_owner != curthread) { + if (access_owner == NULL && + (access_requester == NULL || + access_requester == curthread)) { + access_owner = curthread; + access_requester = NULL; + } else { + if (access_requester == NULL) + access_requester = curthread; + + cv_wait(&access_cv, &access_mtx); + } + } + + mtx_unlock(&access_mtx); +} + +static void +filemon_unlock_write(void) +{ + mtx_lock(&access_mtx); + + /* Sanity check that the current thread actually has the write lock. */ + if (access_owner == curthread) + access_owner = NULL; + + /* Wake up a thread waiting. */ + cv_broadcast(&access_cv); + + mtx_unlock(&access_mtx); +} Added: head/sys/dev/filemon/filemon_wrapper.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/filemon/filemon_wrapper.c Mon Jun 4 22:54:19 2012 (r236592) @@ -0,0 +1,746 @@ +/*- + * Copyright (c) 2011, David E. O'Brien. + * Copyright (c) 2009-2011, Juniper Networks, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#if __FreeBSD_version > 800032 +#define FILEMON_HAS_LINKAT +#endif + +#if __FreeBSD_version < 900044 /* r225617 (2011-09-16) failed to bump + __FreeBSD_version. This really should + be based on "900045". "900044" is r225469 + (2011-09-10) so this code is broken for + 9-CURRENT September 10th-16th. */ +#define sys_chdir chdir +#define sys_execve execve +#define sys_fork fork +#define sys_link link +#define sys_open open +#define sys_rename rename +#define sys_stat stat +#define sys_symlink symlink +#define sys_unlink unlink +#define sys_vfork vfork +#define sys_sys_exit sys_exit +#ifdef FILEMON_HAS_LINKAT +#define sys_linkat linkat +#endif +#endif /* __FreeBSD_version */ + +static void +filemon_output(struct filemon *filemon, char *msg, size_t len) +{ + struct uio auio; + struct iovec aiov; + + if (filemon->fp == NULL) + return; + + aiov.iov_base = msg; + aiov.iov_len = len; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_resid = len; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_rw = UIO_WRITE; + auio.uio_td = curthread; + auio.uio_offset = (off_t) -1; + + bwillwrite(); + + fo_write(filemon->fp, &auio, curthread->td_ucred, 0, curthread); +} + +static struct filemon * +filemon_pid_check(struct proc *p) +{ + struct filemon *filemon; + + TAILQ_FOREACH(filemon, &filemons_inuse, link) { + if (p->p_pid == filemon->pid) + return (filemon); + } + + if (p->p_pptr == NULL) + return (NULL); + + return (filemon_pid_check(p->p_pptr)); +} + +static void +filemon_comment(struct filemon *filemon) +{ + int len; + struct timeval now; + + /* Load timestamp before locking. Less accurate but less contention. */ + getmicrotime(&now); + + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), + "# filemon version %d\n# Target pid %d\n# Start %ju.%06ju\nV %d\n", + FILEMON_VERSION, curproc->p_pid, (uintmax_t)now.tv_sec, + (uintmax_t)now.tv_usec, FILEMON_VERSION); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + + /* Release the read lock. */ + filemon_unlock_read(); +} + +static int +filemon_wrapper_chdir(struct thread *td, struct chdir_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_chdir(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->path, filemon->fname1, + sizeof(filemon->fname1), &done); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "C %d %s\n", + curproc->p_pid, filemon->fname1); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +static int +filemon_wrapper_execve(struct thread *td, struct execve_args *uap) +{ + char fname[MAXPATHLEN]; + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + copyinstr(uap->fname, fname, sizeof(fname), &done); + + if ((ret = sys_execve(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "E %d %s\n", + curproc->p_pid, fname); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) +static int +filemon_wrapper_freebsd32_execve(struct thread *td, + struct freebsd32_execve_args *uap) +{ + char fname[MAXPATHLEN]; + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + copyinstr(uap->fname, fname, sizeof(fname), &done); + + if ((ret = freebsd32_execve(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "E %d %s\n", + curproc->p_pid, fname); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} +#endif + +static int +filemon_wrapper_fork(struct thread *td, struct fork_args *uap) +{ + int ret; + size_t len; + struct filemon *filemon; + + if ((ret = sys_fork(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "F %d %ld\n", + curproc->p_pid, (long)curthread->td_retval[0]); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +static int +filemon_wrapper_open(struct thread *td, struct open_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_open(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->path, filemon->fname1, + sizeof(filemon->fname1), &done); + + if (uap->flags & O_RDWR) { + /* + * We'll get the W record below, but need + * to also output an R to distingish from + * O_WRONLY. + */ + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "R %d %s\n", + curproc->p_pid, filemon->fname1); + filemon_output(filemon, filemon->msgbufr, len); + } + + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "%c %d %s\n", + (uap->flags & O_ACCMODE) ? 'W':'R', + curproc->p_pid, filemon->fname1); + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +static int +filemon_wrapper_rename(struct thread *td, struct rename_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_rename(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->from, filemon->fname1, + sizeof(filemon->fname1), &done); + copyinstr(uap->to, filemon->fname2, + sizeof(filemon->fname2), &done); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "M %d '%s' '%s'\n", + curproc->p_pid, filemon->fname1, filemon->fname2); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +static int +filemon_wrapper_link(struct thread *td, struct link_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_link(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->path, filemon->fname1, + sizeof(filemon->fname1), &done); + copyinstr(uap->link, filemon->fname2, + sizeof(filemon->fname2), &done); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", + curproc->p_pid, filemon->fname1, filemon->fname2); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +static int +filemon_wrapper_symlink(struct thread *td, struct symlink_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_symlink(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->path, filemon->fname1, + sizeof(filemon->fname1), &done); + copyinstr(uap->link, filemon->fname2, + sizeof(filemon->fname2), &done); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", + curproc->p_pid, filemon->fname1, filemon->fname2); + + filemon_output(filemon, filemon->msgbufr, len); + + /* Unlock the found filemon structure. */ + filemon_filemon_unlock(filemon); + } + + /* Release the read lock. */ + filemon_unlock_read(); + } + + return (ret); +} + +#ifdef FILEMON_HAS_LINKAT +static int +filemon_wrapper_linkat(struct thread *td, struct linkat_args *uap) +{ + int ret; + size_t done; + size_t len; + struct filemon *filemon; + + if ((ret = sys_linkat(td, uap)) == 0) { + /* Grab a read lock on the filemon inuse list. */ + filemon_lock_read(); + + if ((filemon = filemon_pid_check(curproc)) != NULL) { + /* Lock the found filemon structure. */ + filemon_filemon_lock(filemon); + + copyinstr(uap->path1, filemon->fname1, + sizeof(filemon->fname1), &done); + copyinstr(uap->path2, filemon->fname2, + sizeof(filemon->fname2), &done); + + len = snprintf(filemon->msgbufr, + sizeof(filemon->msgbufr), "L %d '%s' '%s'\n", + curproc->p_pid, filemon->fname1, filemon->fname2); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***