MFC: r236422, r236592, r236593, r236594, r236620, r236621, r236622, & r236637
filemon(4)
This commit is contained in:
commit
674607983b
@ -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
176
share/man/man4/filemon.4
Normal 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
377
sys/dev/filemon/filemon.c
Normal 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
34
sys/dev/filemon/filemon.h
Normal 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) */
|
122
sys/dev/filemon/filemon_lock.c
Normal file
122
sys/dev/filemon/filemon_lock.c
Normal 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);
|
||||
}
|
746
sys/dev/filemon/filemon_wrapper.c
Normal file
746
sys/dev/filemon/filemon_wrapper.c
Normal 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 */
|
||||
}
|
@ -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
|
||||
|
11
sys/modules/filemon/Makefile
Normal file
11
sys/modules/filemon/Makefile
Normal 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>
|
26
tools/regression/filemon/Makefile
Normal file
26
tools/regression/filemon/Makefile
Normal 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>
|
80
tools/regression/filemon/filemontest.c
Normal file
80
tools/regression/filemon/filemontest.c
Normal 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;
|
||||
}
|
43
tools/regression/filemon/test_script.sh
Executable file
43
tools/regression/filemon/test_script.sh
Executable 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
|
Loading…
x
Reference in New Issue
Block a user