Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 4 Jun 2012 22:54:19 +0000 (UTC)
From:      "David E. O'Brien" <obrien@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r236592 - in head/sys: dev/filemon modules modules/filemon
Message-ID:  <201206042254.q54MsJjn072820@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206042254.q54MsJjn072820>