MFC: r236422, r236592, r236593, r236594, r236620, r236621, r236622, & r236637

filemon(4)
This commit is contained in:
David E. O'Brien 2012-06-06 00:20:13 +00:00
commit 674607983b
11 changed files with 1623 additions and 1 deletions

View File

@ -126,6 +126,7 @@ MAN= aac.4 \
fdt.4 \
fdtbus.4 \
ffclock.4 \
filemon.4 \
firewire.4 \
fpa.4 \
fwe.4 \

176
share/man/man4/filemon.4 Normal file
View File

@ -0,0 +1,176 @@
.\" Copyright (c) 2012
.\" David E. O'Brien <obrien@FreeBSD.org>. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by David E. O'Brien and
.\" contributors.
.\" 4. Neither the name of the author nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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$
.\"
.Dd May 30, 2012
.Dt FILEMON 4
.Os
.Sh NAME
.Nm filemon
.Nd the filemon device
.Sh SYNOPSIS
.In dev/filemon/filemon.h
.Sh DESCRIPTION
The
.Nm
device allows a process to collect file operations data of its children.
The device
.Pa /dev/filemon
responds to two
.Xr ioctl 2
calls.
.Pp
System calls are denoted using the following single letters:
.Pp
.Bl -tag -width indent -compact
.It Ql C
.Xr chdir 2
.It Ql D
.Xr unlink 2
.It Ql E
.Xr exec 2
.It Ql F
.Xr fork 2 ,
.Xr vfork 2
.It Ql L
.Xr link 2 ,
.Xr linkat 2 ,
.Xr symlink 2 ,
.Xr symlinkat 2
.It Ql M
.Xr rename 2
.It Ql R
.Xr open 2
for read
.It Ql S
.Xr stat 2
.It Ql W
.Xr open 2
for write
.It Ql X
.Xr _exit 2
.El
.Pp
Note that
.Ql R
following
.Ql W
records can represent a single
.Xr open 2
for R/W,
or two seperate
.Xr open 2
calls, one for
.Ql R
and one for
.Ql W .
.Sh IOCTLS
User mode programs communicate with the
.Nm
driver through a number of ioctls which are described below.
Each takes a single argument.
.Bl -tag -width ".Dv FILEMON_SET_PID"
.It Dv FILEMON_SET_FD
Write the internal tracing buffer to the supplied open file descriptor.
.It Dv FILEMON_SET_PID
Child process ID to trace.
.El
.Sh RETURN VALUES
.\" .Rv -std ioctl
The
.Fn ioctl
function returns the value 0 if successful;
otherwise the value \-1 is returned and the global variable
.Va errno
is set to indicate the error.
.Sh FILES
.Bl -tag -width ".Pa /dev/filemon"
.It Pa /dev/filemon
.El
.Sh EXAMPLES
.Bd -literal
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <dev/filemon/filemon.h>
#include <fcntl.h>
#include <err.h>
static void
open_filemon(void)
{
pid_t child;
int fm_fd, fm_log;
if ((fm_fd = open("/dev/filemon", O_RDWR)) == -1)
err(1, "open(\e"/dev/filemon\e", O_RDWR)");
if ((fm_log = open("filemon.out",
O_CREAT | O_WRONLY | O_TRUNC, DEFFILEMODE)) == -1)
err(1, "open(filemon.out)");
if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) == -1)
err(1, "Cannot set filemon log file descriptor");
/* Set up these two fd's to close on exec. */
(void)fcntl(fm_fd, F_SETFD, FD_CLOEXEC);
(void)fcntl(fm_log, F_SETFD, FD_CLOEXEC);
if ((child = fork()) == 0) {
child = getpid();
if (ioctl(fm_fd, FILEMON_SET_PID, &child) == -1)
err(1, "Cannot set filemon PID");
/* Do something here. */
return 0;
} else {
wait(&child);
close(fm_fd);
}
return 0;
}
.Ed
.Pp
Creates a file named
.Pa filemon.out
and configures the
.Nm
device to write the
.Nm
buffer contents to it.
.Sh SEE ALSO
.Xr dtrace 1 ,
.Xr ktrace 1 ,
.Xr truss 1
.Sh HISTORY
A
.Nm
device appeared in
.Fx 9.1 .

377
sys/dev/filemon/filemon.c Normal file
View File

@ -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);

34
sys/dev/filemon/filemon.h Normal file
View File

@ -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) */

View File

@ -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);
}

View File

@ -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);
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_stat(struct thread *td, struct stat_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = sys_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);
}
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
static int
filemon_wrapper_freebsd32_stat(struct thread *td,
struct freebsd32_stat_args *uap)
{
int ret;
size_t done;
size_t len;
struct filemon *filemon;
if ((ret = freebsd32_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);
}
#endif
static void
filemon_wrapper_sys_exit(struct thread *td, struct sys_exit_args *uap)
{
size_t len;
struct filemon *filemon;
struct timeval now;
/* Get timestamp before locking. */
getmicrotime(&now);
/* 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 %d\n", curproc->p_pid, uap->rval);
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),
"# Stop %ju.%06ju\n# Bye bye\n",
(uintmax_t)now.tv_sec, (uintmax_t)now.tv_usec);
filemon_output(filemon, filemon->msgbufr, len);
}
/* Unlock the found filemon structure. */
filemon_filemon_unlock(filemon);
}
/* Release the read lock. */
filemon_unlock_read();
sys_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 = sys_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 = sys_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 %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 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;
sv_table[SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
#endif
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
sv_table = ia32_freebsd_sysvec.sv_table;
sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *) filemon_wrapper_chdir;
sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *) filemon_wrapper_sys_exit;
sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_execve;
sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *) filemon_wrapper_fork;
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *) filemon_wrapper_open;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *) filemon_wrapper_rename;
sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *) filemon_wrapper_freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *) filemon_wrapper_unlink;
sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *) filemon_wrapper_vfork;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *) filemon_wrapper_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *) filemon_wrapper_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *) filemon_wrapper_linkat;
#endif
#endif /* COMPAT_ARCH32 */
}
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 *)sys_chdir;
sv_table[SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
sv_table[SYS_execve].sy_call = (sy_call_t *)sys_execve;
sv_table[SYS_fork].sy_call = (sy_call_t *)sys_fork;
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_stat].sy_call = (sy_call_t *)sys_stat;
sv_table[SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
sv_table[SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
#endif
#if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32)
sv_table = ia32_freebsd_sysvec.sv_table;
sv_table[FREEBSD32_SYS_chdir].sy_call = (sy_call_t *)sys_chdir;
sv_table[FREEBSD32_SYS_exit].sy_call = (sy_call_t *)sys_sys_exit;
sv_table[FREEBSD32_SYS_freebsd32_execve].sy_call = (sy_call_t *)freebsd32_execve;
sv_table[FREEBSD32_SYS_fork].sy_call = (sy_call_t *)sys_fork;
sv_table[FREEBSD32_SYS_open].sy_call = (sy_call_t *)sys_open;
sv_table[FREEBSD32_SYS_rename].sy_call = (sy_call_t *)sys_rename;
sv_table[FREEBSD32_SYS_freebsd32_stat].sy_call = (sy_call_t *)freebsd32_stat;
sv_table[FREEBSD32_SYS_unlink].sy_call = (sy_call_t *)sys_unlink;
sv_table[FREEBSD32_SYS_vfork].sy_call = (sy_call_t *)sys_vfork;
sv_table[FREEBSD32_SYS_link].sy_call = (sy_call_t *)sys_link;
sv_table[FREEBSD32_SYS_symlink].sy_call = (sy_call_t *)sys_symlink;
#ifdef FILEMON_HAS_LINKAT
sv_table[FREEBSD32_SYS_linkat].sy_call = (sy_call_t *)sys_linkat;
#endif
#endif /* COMPAT_ARCH32 */
}

View File

@ -5,7 +5,8 @@
# Modules that include binary-only blobs of microcode should be selectable by
# MK_SOURCELESS_UCODE option (see below).
SUBDIR= ${_3dfx} \
SUBDIR= \
${_3dfx} \
${_3dfx_linux} \
${_aac} \
accf_data \
@ -105,6 +106,7 @@ SUBDIR= ${_3dfx} \
fdc \
fdescfs \
${_fe} \
${_filemon} \
firewire \
firmware \
${_fxp} \
@ -356,6 +358,10 @@ SUBDIR= ${_3dfx} \
${_zfs} \
zlib \
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
_filemon= filemon
.endif
.if ${MACHINE_CPUARCH} != "powerpc" && ${MACHINE_CPUARCH} != "arm" && \
${MACHINE_CPUARCH} != "mips"
_syscons= syscons

View File

@ -0,0 +1,11 @@
# $FreeBSD$
MAINTAINER= obrien@FreeBSD.org
.PATH: ${.CURDIR}/../../dev/filemon
KMOD= filemon
SRCS= ${KMOD}.c
SRCS+= vnode_if.h opt_compat.h opt_capsicum.h
.include <bsd.kmod.mk>

View File

@ -0,0 +1,26 @@
# $FreeBSD$
PROG= filemontest
NO_MAN=
WARNS?= 6
CFLAGS+= -I${.CURDIR}/../../../sys
# Cannot use .OBJDIR -- 'filemontest' expects 'test_script.sh' in .
test: ${PROG} clean-test
cd ${.CURDIR} ; \
for A in 1 2 3 4 5 6 7 8 9 0; do \
for B in 1 2 3 4 5 6 7 8 9 0; do \
for C in 1 2 3 4 5 6 7 8 9 0; do \
${.OBJDIR}/${PROG} ;\
done ;\
done ;\
done
@cd ${.CURDIR} ; set +e ; egrep '(Start|Stop) .*\.' filemon_log.* | \
grep -q -v '\.[0-9][0-9][0-9][0-9][0-9][0-9]$$' || echo "Time stamp format OK"
clean-test:
cd ${.CURDIR} ; rm -f filemon_log.*
.include <bsd.prog.mk>

View File

@ -0,0 +1,80 @@
/*-
* 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/types.h>
__FBSDID("$FreeBSD$");
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <dev/filemon/filemon.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <err.h>
/*
* This simple test of filemon expects a test script called
* "test_script.sh" in the cwd.
*/
int
main(void) {
char log_name[] = "filemon_log.XXXXXX";
pid_t child;
int fm_fd, fm_log;
if ((fm_fd = open("/dev/filemon", O_RDWR)) == -1)
err(1, "open(\"/dev/filemon\", O_RDWR)");
if ((fm_log = mkstemp(log_name)) == -1)
err(1, "mkstemp(%s)", log_name);
if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) == -1)
err(1, "Cannot set filemon log file descriptor");
/* Set up these two fd's to close on exec. */
(void)fcntl(fm_fd, F_SETFD, FD_CLOEXEC);
(void)fcntl(fm_log, F_SETFD, FD_CLOEXEC);
switch (child = fork()) {
case 0:
child = getpid();
if (ioctl(fm_fd, FILEMON_SET_PID, &child) == -1)
err(1, "Cannot set filemon PID to %d", child);
system("./test_script.sh");
break;
case -1:
err(1, "Cannot fork");
default:
wait(&child);
close(fm_fd);
// printf("Results in %s\n", log_name);
break;
}
return 0;
}

View File

@ -0,0 +1,43 @@
#! /bin/sh
#
# Copyright (c) 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$
trap 'rm -f $f1 $f2; exit 1' 1 2 3 13 15
echo shazbot > /dev/null
f1=`mktemp /tmp/filemon_test.XXXXXX`
f2=`mktemp /tmp/ed-script.XXXXXX`
> $f1
echo "One line to rule them all" >> $f1
wc -l $f1 > /dev/null
# ed(1)'s /tmp/ed.* buffer file will be opened RW
echo ',s/$/./g' > $f2
echo 'wq' >>$f2
ed -s $f1 < $f2
#echo ",s/$/./\
#w" | ed -s $f1
#rm $f1 $f2
uptime > /dev/null