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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/condvar.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/ioccom.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/poll.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/syscall.h>
+#include <sys/sysent.h>
+#include <sys/sysproto.h>
+#include <sys/uio.h>
+
+#if __FreeBSD_version >= 900041
+#include <sys/capability.h>
+#endif
+
+#include "filemon.h"
+
+#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
+#include <compat/freebsd32/freebsd32_syscall.h>
+#include <compat/freebsd32/freebsd32_proto.h>
+
+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 <sys/cdefs.h>
+__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 <sys/cdefs.h>
+__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 ***
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to