Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 May 2009 22:16:14 +0000 (UTC)
From:      John Birrell <jb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r192702 - in projects/jbuild/usr.bin/jbuild: . filemon
Message-ID:  <200905242216.n4OMGERa002815@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jb
Date: Sun May 24 22:16:14 2009
New Revision: 192702
URL: http://svn.freebsd.org/changeset/base/192702

Log:
  Add jbuild, a modified version of FreeBSD's 'make' with automated dependency
  handling.
  
  filemon is a kernel module that provides a device interface for jbuild to read
  info that it saves in the meta data file for each target built.

Added:
  projects/jbuild/usr.bin/jbuild/
  projects/jbuild/usr.bin/jbuild/Makefile
  projects/jbuild/usr.bin/jbuild/filemon/
  projects/jbuild/usr.bin/jbuild/filemon/Makefile
  projects/jbuild/usr.bin/jbuild/filemon/filemon.c
  projects/jbuild/usr.bin/jbuild/filemon/filemon.h
  projects/jbuild/usr.bin/jbuild/filemon/filemon_lock.c
  projects/jbuild/usr.bin/jbuild/filemon/filemon_wrapper.c

Added: projects/jbuild/usr.bin/jbuild/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/Makefile	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,125 @@
+# $FreeBSD$
+
+.PATH		: ${.CURDIR}/../make ${.CURDIR}/../jdirdep
+
+PROG=		jbuild
+CFLAGS+=	-I${.CURDIR}/../make
+SRCS=		arch.c buf.c cond.c dir.c for.c hash.c hash_tables.c job.c	\
+		lst.c main.c make.c \
+		parse.c proc.c shell.c str.c suff.c targ.c	\
+		util.c var.c
+
+BINDIR?=	/usr/local/bin
+WARNS?=		6
+NO_SHARED?=	YES
+NO_MAN=
+IGNORE_PRAGMA=	YES
+DEBUG_FLAGS+=	-g
+
+CFLAGS+=	-DMAKE_VERSION=\"8000000000\"
+
+# We're building 'build', not 'make' so the behaviour is different in
+# some areas like defaulting to silent.
+CFLAGS+=	-DMAKE_IS_BUILD -DJBUILD
+
+.ifdef BUILDMON
+SRCS += buildmonreq.c
+CFLAGS += -DBUILDMON -I${.CURDIR}/buildmon
+.else
+CFLAGS += -I${.CURDIR}/filemon
+.endif
+
+.include "${.CURDIR}/../jdirdep/Makefile.common"
+
+# Make object files which depend on preprocessor symbols defined in
+# the Makefile which are not compilation options but rather configuration
+# options dependend on the Makefile. main.c needs MAKE_VERSION while
+# shell.c uses DEFSHELLNAME. This will cause recompilation in the case
+# the definition is changed in the makefile. It will of course not cause
+# recompilation if one does 'make MAKE_SHELL=csh'.
+main.o shell.o: ${MAKEFILE}
+
+# Directive and keyword tables. We use hash tables. These hash tables have been
+# generated with mph (ports/devel/mph)
+# If you change the directives or keywords (adding, deleting, reordering) you
+# need to create new tables and hash functions (directive_hash, keyword_hash).
+#
+# The following changes have been made to the generated code:
+#
+#	o prefix the names of the g, T0 and T1 arrays with 'directive_'
+#	  resp. 'keyword_'.
+#
+#	o make the type of the tables 'const [un]signed char' (if you change
+#	  anything make sure that the numbers fit into a char).
+#
+#	o make the hash function use the length for termination,
+#	  not the trailing '\0', via the -l flag in emitc and some editing
+#	  (only for directive_hash).
+
+LOCALBASE ?= /usr/local
+MPH	?= ${LOCALBASE}/bin/mph
+EMITC	?= ${LOCALBASE}/bin/emitc
+
+.PRECIOUS: hash
+
+hash:
+	( echo '/*' ;							\
+	  echo ' * DO NOT EDIT' ;					\
+	  echo ' * $$''FreeBSD$$' ;					\
+	  echo -n ' * auto-generated from ' ;				\
+	  sed -nEe '/\$$FreeBSD/s/^.*\$$(.*)\$$.*$$/\1/p'		\
+		${.CURDIR}/parse.c ;					\
+	  echo ' * DO NOT EDIT' ;					\
+	  echo ' */' ;							\
+	  echo '#include <sys/types.h>' ;				\
+	  echo ;							\
+	  echo '#include "hash_tables.h"' ;				\
+	  echo ;							\
+	  cat ${.CURDIR}/parse.c | sed					\
+	    -e '1,/DIRECTIVES-START-TAG/d'				\
+	    -e '/DIRECTIVES-END-TAG/,$$d'				\
+	    -e 's/^[^"]*"\([^"]*\)".*$$/\1/' |				\
+	    ${MPH} -d2 -m1 | ${EMITC} -l -s |				\
+	    sed								\
+	    -e 's/^static int g\[\]/static const signed char directive_g[]/' \
+	    -e 's/^static int T0\[\]/static const u_char directive_T0[]/' \
+	    -e 's/^static int T1\[\]/static const u_char directive_T1[]/' \
+	    -e '/^#define uchar unsigned char/d'			\
+	    -e 's/uchar/u_char/g'					\
+	    -e 's/^hash(/directive_hash(/'				\
+	    -e 's/; \*kp;/; kp < key + len;/'				\
+	    -e 's/int len)/size_t len)/'				\
+	    -e 's/= T0\[/= directive_T0\[/'				\
+	    -e 's/= T1\[/= directive_T1\[/'				\
+	    -e 's/g\[f/directive_g[f/g' ;				\
+	  cat ${.CURDIR}/parse.c | sed					\
+	    -e '1,/KEYWORD-START-TAG/d'					\
+	    -e '/KEYWORD-END-TAG/,$$d'					\
+	    -e 's/^[^"]*"\([^"]*\)".*$$/\1/' |				\
+	    ${MPH} -d2 -m1 | ${EMITC} -l -s |				\
+	    sed								\
+	    -e 's/^static int g\[\]/static const signed char keyword_g[]/' \
+	    -e 's/^static int T0\[\]/static const u_char keyword_T0[]/' \
+	    -e 's/^static int T1\[\]/static const u_char keyword_T1[]/' \
+	    -e '/^#define uchar unsigned char/d'			\
+	    -e 's/uchar/u_char/g'					\
+	    -e 's/^hash(/keyword_hash(/'				\
+	    -e 's/int len)/size_t len)/'				\
+	    -e 's/= T0\[/= keyword_T0\[/'				\
+	    -e 's/= T1\[/= keyword_T1\[/'				\
+	    -e 's/g\[f/keyword_g[f/g'					\
+	) > ${.CURDIR}/hash_tables.c
+
+# Set the shell which make(1) uses.  Bourne is the default, but a decent
+# Korn shell works fine, and much faster.  Using the C shell for this
+# will almost certainly break everything, but it's Unix tradition to
+# allow you to shoot yourself in the foot if you want to :-)
+
+MAKE_SHELL?=	sh
+.if ${MAKE_SHELL} == "csh" || ${MAKE_SHELL} == "sh" || ${MAKE_SHELL} == "ksh"
+CFLAGS+=	-DDEFSHELLNAME=\"${MAKE_SHELL}\"
+.else
+.error "MAKE_SHELL must be set to one of \"csh\", \"sh\" or \"ksh\"."
+.endif
+
+.include <bsd.prog.mk>

Added: projects/jbuild/usr.bin/jbuild/filemon/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/filemon/Makefile	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+KMOD = filemon
+SRCS = filemon.c
+SRCS += vnode_if.h
+
+.include <bsd.kmod.mk>

Added: projects/jbuild/usr.bin/jbuild/filemon/filemon.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/filemon/filemon.c	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,310 @@
+/* $FreeBSD$ */
+
+#include <sys/cdefs.h>
+#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>
+#include "filemon.h"
+
+extern struct sysentvec elf32_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 {
+	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. */
+	struct file
+		*fp;			/* Output file pointer. */
+	struct thread
+		*locker;		/* Ptr to the thread locking this */
+					/* filemon.*/
+	struct mtx
+		mtx;			/* Lock mutex for this filemon. */
+	struct cv
+		cv;			/* Lock condition variable for this */
+					/* filemon. */
+	TAILQ_ENTRY(filemon) link;	/* Link into the in-use list. */
+};
+
+static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse);
+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) {
+		/* Get exclusive write access. */
+		filemon_lock_write();
+
+		/* Remove from the in-use list. */
+		TAILQ_REMOVE(&filemons_inuse, filemon, link);
+
+		/* Give up write access. */
+		filemon_unlock_write();
+
+		if (filemon->fp != NULL)
+			fdrop(filemon->fp, curthread);
+
+		mtx_destroy(&filemon->mtx);
+		cv_destroy(&filemon->cv);
+
+		free(filemon, M_FILEMON);
+	}
+}
+
+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 ((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;
+
+	filemon = malloc(sizeof(struct filemon), M_FILEMON, M_WAITOK | M_ZERO);
+
+	filemon->pid = curproc->p_pid;
+	filemon->fp = NULL;
+
+	mtx_init(&filemon->mtx, "filemon", "filemon", MTX_DEF);
+	cv_init(&filemon->cv, "filemon");
+
+#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)
+{
+	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
+
+		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: projects/jbuild/usr.bin/jbuild/filemon/filemon.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/filemon/filemon.h	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,4 @@
+/* $FreeBSD$ */
+
+#define FILEMON_SET_FD		_IOWR('S', 1, int)
+#define FILEMON_SET_PID		_IOWR('S', 2, pid_t)

Added: projects/jbuild/usr.bin/jbuild/filemon/filemon_lock.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/filemon/filemon_lock.c	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,94 @@
+/* $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: projects/jbuild/usr.bin/jbuild/filemon/filemon_wrapper.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/jbuild/usr.bin/jbuild/filemon/filemon_wrapper.c	Sun May 24 22:16:14 2009	(r192702)
@@ -0,0 +1,410 @@
+/* $FreeBSD$ */
+
+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;
+
+	/* 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),
+	    "# buildmon version 2\n# Target pid %d\nV 2\n", curproc->p_pid);
+
+	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 = 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 = 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);
+}
+
+static int
+filemon_wrapper_fork(struct thread *td, struct fork_args *uap)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = 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 %d\n",
+			    curproc->p_pid, 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 = 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);
+
+			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 = 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_stat(struct thread *td, struct stat_args *uap)
+{
+	int ret;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = stat(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), "S %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 void
+filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
+{
+	size_t len;
+	struct filemon *filemon;
+
+	/* 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), "X %d\n", curproc->p_pid);
+
+		filemon_output(filemon, filemon->msgbufr, len);
+
+		/* Check if the monitored process is about to exit. */
+		if (filemon->pid == curproc->p_pid) {
+			len = snprintf(filemon->msgbufr, sizeof(filemon->msgbufr), "# Bye bye\n");
+
+			filemon_output(filemon, filemon->msgbufr, len);
+		}
+
+		/* Unlock the found filemon structure. */
+		filemon_filemon_unlock(filemon);
+	}
+
+	/* Release the read lock. */
+	filemon_unlock_read();
+
+	sys_exit(td, uap);
+}
+
+static int
+filemon_wrapper_unlink(struct thread *td, struct unlink_args *uap)
+{
+	int ret;
+	size_t done;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = unlink(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), "D %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_vfork(struct thread *td, struct vfork_args *uap)
+{
+	int ret;
+	size_t len;
+	struct filemon *filemon;
+
+	if ((ret = vfork(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 %d\n",
+			    curproc->p_pid, 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 void
+filemon_wrapper_install(void)
+{
+#if defined(__i386__)
+	struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
+#elif defined(__amd64__)
+	struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
+#else
+#error Machine type not supported
+#endif
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) filemon_wrapper_execve;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
+	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_stat].sy_call = (sy_call_t *) filemon_wrapper_stat;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
+}
+
+static void
+filemon_wrapper_deinstall(void)
+{
+#if defined(__i386__)
+	struct sysent *sv_table = elf32_freebsd_sysvec.sv_table;
+#elif defined(__amd64__)
+	struct sysent *sv_table = elf64_freebsd_sysvec.sv_table;
+#else
+#error Machine type not supported
+#endif
+
+	sv_table[SYS_chdir].sy_call = (sy_call_t *) chdir;
+	sv_table[SYS_exit].sy_call = (sy_call_t *) sys_exit;
+	sv_table[SYS_execve].sy_call = (sy_call_t *) execve;
+	sv_table[SYS_fork].sy_call = (sy_call_t *) fork;
+	sv_table[SYS_open].sy_call = (sy_call_t *) open;
+	sv_table[SYS_rename].sy_call = (sy_call_t *) rename;
+	sv_table[SYS_stat].sy_call = (sy_call_t *) stat;
+	sv_table[SYS_unlink].sy_call = (sy_call_t *) unlink;
+	sv_table[SYS_vfork].sy_call = (sy_call_t *) vfork;
+}



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