Module Name:    src
Committed By:   sjg
Date:           Thu Sep  9 00:10:16 UTC 2010

Added Files:
        src/sys/dev/filemon: filemon.c filemon.h filemon_wrapper.c mknod-sh
        src/sys/modules/filemon: Makefile

Log Message:
First cut of simple syscall wrapper, which make(1) can use
to track process activity.


To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/sys/dev/filemon/filemon.c \
    src/sys/dev/filemon/filemon.h src/sys/dev/filemon/filemon_wrapper.c \
    src/sys/dev/filemon/mknod-sh
cvs rdiff -u -r0 -r1.1 src/sys/modules/filemon/Makefile

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Added files:

Index: src/sys/dev/filemon/filemon.c
diff -u /dev/null src/sys/dev/filemon/filemon.c:1.1
--- /dev/null	Thu Sep  9 00:10:16 2010
+++ src/sys/dev/filemon/filemon.c	Thu Sep  9 00:10:16 2010
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT
+ * OWNER 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>
+__KERNEL_RCSID(0, "$NetBSD: filemon.c,v 1.1 2010/09/09 00:10:16 sjg Exp $");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/fcntl.h>
+#include <sys/rwlock.h>
+#include <sys/condvar.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/kmem.h>
+#include <sys/syslog.h>
+
+#include "filemon.h"
+
+MODULE(MODULE_CLASS_DRIVER, filemon, NULL);
+
+static dev_type_open(filemon_open);
+
+static struct cdevsw filemon_cdevsw = {
+	.d_open = filemon_open,
+	.d_flag = D_MPSAFE,
+	.d_close = noclose,
+	.d_read = noread,
+	.d_write = nowrite,
+	.d_ioctl = noioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = nopoll,
+	.d_mmap = nommap,
+	.d_kqfilter = nokqfilter,
+};
+
+static int filemon_ioctl(struct file *, u_long, void *);
+static int filemon_close(struct file *);
+
+static const struct fileops filemon_fileops = {
+	.fo_ioctl = filemon_ioctl,
+	.fo_close = filemon_close,
+	.fo_read = fbadop_read,
+	.fo_write = fbadop_write,
+	.fo_fcntl = fnullop_fcntl,
+	.fo_poll = fnullop_poll,
+	.fo_stat = fbadop_stat,
+	.fo_kqfilter = fnullop_kqfilter,
+};
+
+static krwlock_t filemon_mtx;
+
+static TAILQ_HEAD(, filemon) filemons_inuse =
+	TAILQ_HEAD_INITIALIZER(filemons_inuse);
+
+#ifdef DEBUG
+static int logLevel = LOG_DEBUG;
+#endif
+
+void
+filemon_output(struct filemon * filemon, char *msg, size_t len)
+{
+	struct uio auio;
+	struct iovec aiov;
+
+	if (filemon->fm_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_rw = UIO_WRITE;
+	auio.uio_offset = (off_t) - 1;
+	uio_setup_sysspace(&auio);
+
+#ifdef DEBUG
+	{
+		char *cp;
+		int x = 16;
+
+		cp = strchr(msg, '\n');
+		if (cp && cp - msg <= 16)
+			x = (cp - msg) - 2;
+		log(logLevel, "filemont_output:('%.*s%s'", x,
+		    (x < 16) ? "..." : "", msg);
+	}
+#endif
+	(*filemon->fm_fp->f_ops->fo_write) (filemon->fm_fp,
+	    &(filemon->fm_fp->f_offset),
+	    &auio, curlwp->l_cred, FOF_UPDATE_OFFSET);
+}
+
+static void
+filemon_comment(struct filemon * filemon)
+{
+	int len;
+
+	len = snprintf(filemon->fm_msgbufr, sizeof(filemon->fm_msgbufr),
+	    "# filemon version 2\n# Target pid %d\nV 2\n",
+	    curproc->p_pid);
+
+	filemon_output(filemon, filemon->fm_msgbufr, len);
+}
+
+
+static struct filemon *
+filemon_pid_check(struct proc * p)
+{
+	struct filemon *filemon;
+
+	TAILQ_FOREACH(filemon, &filemons_inuse, fm_link) {
+		if (p->p_pid == filemon->fm_pid)
+			return (filemon);
+	}
+
+	if (p->p_pptr == NULL)
+		return (NULL);
+
+	return (filemon_pid_check(p->p_pptr));
+}
+
+/*
+ * return exclusive access to a filemon struct
+ */
+struct filemon *
+filemon_lookup(struct proc * p)
+{
+	struct filemon *filemon;
+
+	rw_enter(&filemon_mtx, RW_READER);
+	filemon = filemon_pid_check(p);
+	if (filemon) {
+		rw_enter(&filemon->fm_mtx, RW_WRITER);
+	}
+	rw_exit(&filemon_mtx);
+	return filemon;
+}
+
+static struct filemon *
+filemon_fp_data(struct file * fp, int lck)
+{
+	struct filemon *filemon;
+	
+	rw_enter(&filemon_mtx, RW_READER);
+	filemon = fp->f_data;
+	if (filemon && lck) {
+		rw_enter(&filemon->fm_mtx, lck);
+	}
+	rw_exit(&filemon_mtx);
+	return filemon;
+}
+
+static int n_open = 0;
+
+static int
+filemon_open(dev_t dev, int oflags __unused, int mode __unused,
+    struct lwp * l __unused)
+{
+	struct filemon *filemon;
+	struct file *fp;
+	int error, fd;
+
+	/* falloc() will use the descriptor for us. */
+	if ((error = fd_allocfile(&fp, &fd)) != 0)
+		return error;
+
+	filemon = kmem_alloc(sizeof(struct filemon), KM_SLEEP);
+	if (!filemon)
+		return ENOMEM;
+
+	rw_init(&filemon->fm_mtx);
+	filemon->fm_fd = -1;
+	filemon->fm_fp = NULL;
+	filemon->fm_pid = curproc->p_pid;
+
+	rw_enter(&filemon_mtx, RW_WRITER);
+	n_open++;
+
+	TAILQ_INSERT_TAIL(&filemons_inuse, filemon, fm_link);
+
+	rw_exit(&filemon_mtx);
+	return fd_clone(fp, fd, oflags, &filemon_fileops, filemon);
+}
+
+
+static int
+filemon_close(struct file * fp)
+{
+	struct filemon *filemon;
+
+#ifdef DEBUG
+	log(logLevel, "filemon_close()");
+#endif
+	/*
+	 * Follow the same lock order as filemon_lookup()
+	 * and filemon_fp_data() but hold exclusive access to
+	 * filemon_mtx until we are done.
+	 */
+	rw_enter(&filemon_mtx, RW_WRITER);
+	filemon = fp->f_data;
+	if (!filemon) {
+		rw_exit(&filemon_mtx);
+		return EBADF;
+	}
+	/* ensure that filemon_lookup() will now fail */
+	TAILQ_REMOVE(&filemons_inuse, filemon, fm_link);
+	n_open--;
+	/* ensure that filemon_fp_data() will now fail */
+	fp->f_data = NULL;
+
+	/*
+	 * once we have exclusive access, it should never be used again
+	 */
+	rw_enter(&filemon->fm_mtx, RW_WRITER);
+	if (filemon->fm_fp) {
+		fd_putfile(filemon->fm_fd);	/* release our reference */
+		filemon->fm_fp = NULL;
+	}
+	rw_exit(&filemon->fm_mtx);
+	rw_destroy(&filemon->fm_mtx);
+	kmem_free(filemon, sizeof(struct filemon));
+	rw_exit(&filemon_mtx);
+	return (0);
+}
+
+static int
+filemon_ioctl(struct file * fp, u_long cmd, void *data)
+{
+	int error = 0;
+	struct filemon *filemon;
+
+
+#ifdef DEBUG
+	log(logLevel, "filemon_ioctl(%lu)", cmd);;
+#endif
+
+	/*
+	 * this ensures we cannot get filemon if it is closing.
+	 */
+	filemon = filemon_fp_data(fp, RW_WRITER);
+	if (!filemon)
+		return EBADF;
+
+	switch (cmd) {
+	case FILEMON_SET_FD:
+		/* Set the output file descriptor. */
+		filemon->fm_fd = *((int *) data);
+		if ((filemon->fm_fp = fd_getfile(filemon->fm_fd)) == NULL) {
+			rw_exit(&filemon->fm_mtx);
+			return EBADF;
+		}
+		/* Write the file header. */
+		filemon_comment(filemon);
+		break;
+
+	case FILEMON_SET_PID:
+		/* Set the monitored process ID. */
+		filemon->fm_pid = *((pid_t *) data);
+		break;
+
+	default:
+		error = EINVAL;
+		break;
+	}
+
+	rw_exit(&filemon->fm_mtx);
+	return (error);
+}
+
+static void
+filemon_load(void *dummy __unused)
+{
+	rw_init(&filemon_mtx);
+
+	/* Install the syscall wrappers. */
+	filemon_wrapper_install();
+}
+
+
+static int
+filemon_unload(void)
+{
+	int error = 0;
+
+	rw_enter(&filemon_mtx, RW_WRITER);
+
+	if (TAILQ_FIRST(&filemons_inuse) != NULL)
+		error = EBUSY;
+	else {
+		/* Deinstall the syscall wrappers. */
+		filemon_wrapper_deinstall();
+	}
+	rw_exit(&filemon_mtx);
+
+	if (error == 0) {
+		rw_destroy(&filemon_mtx);
+	}
+	return (error);
+}
+
+static int
+filemon_modcmd(modcmd_t cmd, void *data)
+{
+	int error = 0;
+	int bmajor = -1;
+	int cmajor = -1;
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef DEBUG
+		logLevel = LOG_INFO;
+#endif
+
+		filemon_load(data);
+		error = devsw_attach("filemon", NULL, &bmajor,
+		    &filemon_cdevsw, &cmajor);
+		break;
+
+	case MODULE_CMD_FINI:
+		error = filemon_unload();
+		if (!error)
+			error = devsw_detach(NULL, &filemon_cdevsw);
+		break;
+
+	case MODULE_CMD_STAT:
+		log(LOG_INFO, "filemon: open=%d", n_open);
+		break;
+
+	default:
+		error = EOPNOTSUPP;
+		break;
+
+	}
+
+	return (error);
+}
Index: src/sys/dev/filemon/filemon.h
diff -u /dev/null src/sys/dev/filemon/filemon.h:1.1
--- /dev/null	Thu Sep  9 00:10:16 2010
+++ src/sys/dev/filemon/filemon.h	Thu Sep  9 00:10:16 2010
@@ -0,0 +1,52 @@
+/* $NetBSD: filemon.h,v 1.1 2010/09/09 00:10:16 sjg Exp $ */
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT
+ * OWNER 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.
+ */
+#ifndef FILEMON_SET_FD
+
+#ifndef _PATH_FILEMON
+#define _PATH_FILEMON "/dev/filemon"
+#endif
+#define FILEMON_SET_FD		_IOWR('S', 1, int)
+#define FILEMON_SET_PID		_IOWR('S', 2, pid_t)
+
+#ifdef _KERNEL
+struct filemon {
+	pid_t fm_pid;		/* The process ID being monitored. */
+	char fm_fname1[MAXPATHLEN];/* Temporary filename buffer. */
+	char fm_fname2[MAXPATHLEN];/* Temporary filename buffer. */
+	char fm_msgbufr[32 + 2 * MAXPATHLEN];	/* Output message buffer. */
+	int fm_fd;			/* Output fd */
+	struct file *fm_fp;	/* Output file pointer. */
+	krwlock_t fm_mtx;		/* Lock mutex for this filemon. */
+	TAILQ_ENTRY(filemon) fm_link;	/* Link into the in-use list. */
+};
+
+struct filemon * filemon_lookup(struct proc *);
+void filemon_output(struct filemon *, char *, size_t);
+void filemon_wrapper_install(void);
+void filemon_wrapper_deinstall(void);
+#endif
+
+#endif
Index: src/sys/dev/filemon/filemon_wrapper.c
diff -u /dev/null src/sys/dev/filemon/filemon_wrapper.c:1.1
--- /dev/null	Thu Sep  9 00:10:16 2010
+++ src/sys/dev/filemon/filemon_wrapper.c	Thu Sep  9 00:10:16 2010
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2010, Juniper Networks, Inc.
+ *
+ * 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 THE COPYRIGHT HOLDERS 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 THE COPYRIGHT
+ * OWNER 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>
+__KERNEL_RCSID(0, "$NetBSD: filemon_wrapper.c,v 1.1 2010/09/09 00:10:16 sjg Exp $");
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/lwp.h>
+#include <sys/proc.h>
+#include <sys/syscall.h>
+#include <sys/syscallargs.h>
+
+#include "filemon.h"
+
+static int
+filemon_wrapper_chdir(struct lwp * l, const struct sys_chdir_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+	
+	if ((ret = sys_chdir(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+
+			error = copyinstr(SCARG(uap, path), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "C %d %s\n",
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_execve(struct lwp * l, struct sys_execve_args * uap,
+    register_t * retval)
+{
+	char fname[MAXPATHLEN];
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+	
+	error = copyinstr(SCARG(uap, path), fname, sizeof(fname), &done);
+
+	if ((ret = sys_execve(l, uap, retval)) == 0 && error == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+
+			len = snprintf(filemon->fm_msgbufr, sizeof(filemon->fm_msgbufr),
+			    "E %d %s\n",
+			    curproc->p_pid, fname);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+static int
+filemon_wrapper_fork(struct lwp * l, const void *v, register_t * retval)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_fork(l, v, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr),
+			    "F %d %ld\n",
+			    curproc->p_pid, (long) retval[0]);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_vfork(struct lwp * l, const void *v, register_t * retval)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_vfork(l, v, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr),
+			    "F %d %ld\n",
+			    curproc->p_pid, (long) retval[0]);
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_open(struct lwp * l, struct sys_open_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_open(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "%c %d %s\n",
+				    (SCARG(uap, flags) & O_ACCMODE) ? 'W' : 'R',
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_rename(struct lwp * l, struct sys_rename_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_rename(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, from), filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) 
+				error = copyinstr(SCARG(uap, to),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "M %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_link(struct lwp * l, struct sys_link_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_link(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1, sizeof(filemon->fm_fname1),
+			    &done);
+			if (error == 0)
+				error = copyinstr(SCARG(uap, link),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr), "L %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+static int
+filemon_wrapper_symlink(struct lwp * l, struct sys_symlink_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_symlink(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0)
+				error = copyinstr(SCARG(uap, link),
+				    filemon->fm_fname2,
+				    sizeof(filemon->fm_fname2), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "L %d '%s' '%s'\n",
+				    curproc->p_pid, filemon->fm_fname1,
+				    filemon->fm_fname2);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+static void
+filemon_wrapper_sys_exit(struct lwp * l, struct sys_exit_args * uap,
+    register_t * retval)
+{
+	size_t len;
+	struct filemon *filemon;
+
+	filemon = filemon_lookup(curproc);
+
+	if (filemon) {
+		len = snprintf(filemon->fm_msgbufr,
+		    sizeof(filemon->fm_msgbufr), "X %d %d\n",
+		    curproc->p_pid, SCARG(uap, rval));
+
+		filemon_output(filemon, filemon->fm_msgbufr, len);
+
+		/* Check if the monitored process is about to exit. */
+		if (filemon->fm_pid == curproc->p_pid) {
+			len = snprintf(filemon->fm_msgbufr,
+			    sizeof(filemon->fm_msgbufr), "# Bye bye\n");
+
+			filemon_output(filemon, filemon->fm_msgbufr, len);
+		}
+		rw_exit(&filemon->fm_mtx);
+	}
+	sys_exit(l, uap, retval);
+}
+
+static int
+filemon_wrapper_unlink(struct lwp * l, struct sys_unlink_args * uap,
+    register_t * retval)
+{
+	int ret;
+	int error;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = sys_unlink(l, uap, retval)) == 0) {
+		filemon = filemon_lookup(curproc);
+
+		if (filemon) {
+			error = copyinstr(SCARG(uap, path),
+			    filemon->fm_fname1,
+			    sizeof(filemon->fm_fname1), &done);
+			if (error == 0) {
+				len = snprintf(filemon->fm_msgbufr,
+				    sizeof(filemon->fm_msgbufr),
+				    "D %d %s\n",
+				    curproc->p_pid, filemon->fm_fname1);
+
+				filemon_output(filemon, filemon->fm_msgbufr,
+				    len);
+			}
+			rw_exit(&filemon->fm_mtx);
+		}
+	}
+	return (ret);
+}
+
+
+void
+filemon_wrapper_install(void)
+{
+	struct sysent *sv_table = curproc->p_emul->e_sysent;
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
+	sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
+	sv_table[SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
+	sv_table[SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
+	sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
+}
+
+void
+filemon_wrapper_deinstall(void)
+{
+	struct sysent *sv_table = curproc->p_emul->e_sysent;
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) sys_chdir;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) sys_execve;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) sys_exit;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) sys_fork;
+	sv_table[SYS_link].sy_call = (sy_call_t *) sys_link;
+	sv_table[SYS_open].sy_call = (sy_call_t *) sys_open;
+	sv_table[SYS_rename].sy_call = (sy_call_t *) sys_rename;
+	sv_table[SYS_symlink].sy_call = (sy_call_t *) sys_symlink;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) sys_unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) sys_vfork;
+}
Index: src/sys/dev/filemon/mknod-sh
diff -u /dev/null src/sys/dev/filemon/mknod-sh:1.1
--- /dev/null	Thu Sep  9 00:10:16 2010
+++ src/sys/dev/filemon/mknod-sh	Thu Sep  9 00:10:16 2010
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Note that filemon.kmod needs the 6.x version of modload.
+
+Error() {
+	echo "ERROR: $@" >&2; exit 1
+}
+
+major=`sysctl kern.drivers | tr ',' '\012' | sed -n '/filemon/s,.*\[\([0-9][0-9]*\).*,\1,p'`
+
+[ ${major:-0} -gt 0 ] || Error filemon not loaded
+dev=/dev/filemon
+
+if [ -c $dev ]; then
+   x=`'ls' -l $dev`
+   case "$x" in
+   *" $major,"*) exit 0;;
+   esac
+   rm -f $dev
+fi
+mknod -m 666 $dev c $major 0
+

Index: src/sys/modules/filemon/Makefile
diff -u /dev/null src/sys/modules/filemon/Makefile:1.1
--- /dev/null	Thu Sep  9 00:10:16 2010
+++ src/sys/modules/filemon/Makefile	Thu Sep  9 00:10:16 2010
@@ -0,0 +1,11 @@
+# $NetBSD: Makefile,v 1.1 2010/09/09 00:10:16 sjg Exp $
+
+.include "../Makefile.inc"
+
+.PATH: ${S}/dev/filemon
+
+KMOD = filemon
+SRCS = filemon.c filemon_wrapper.c
+NOMAN = no
+
+.include <bsd.kmodule.mk>

Reply via email to