1*eb9aea5aSDavid E. O'Brien /*- 2*eb9aea5aSDavid E. O'Brien * Copyright (c) 2011, David E. O'Brien. 3*eb9aea5aSDavid E. O'Brien * Copyright (c) 2009-2011, Juniper Networks, Inc. 4*eb9aea5aSDavid E. O'Brien * All rights reserved. 5*eb9aea5aSDavid E. O'Brien * 6*eb9aea5aSDavid E. O'Brien * Redistribution and use in source and binary forms, with or without 7*eb9aea5aSDavid E. O'Brien * modification, are permitted provided that the following conditions 8*eb9aea5aSDavid E. O'Brien * are met: 9*eb9aea5aSDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright 10*eb9aea5aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer. 11*eb9aea5aSDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright 12*eb9aea5aSDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the 13*eb9aea5aSDavid E. O'Brien * documentation and/or other materials provided with the distribution. 14*eb9aea5aSDavid E. O'Brien * 15*eb9aea5aSDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS AND CONTRIBUTORS ``AS IS'' AND 16*eb9aea5aSDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*eb9aea5aSDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*eb9aea5aSDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL JUNIPER NETWORKS OR CONTRIBUTORS BE LIABLE 19*eb9aea5aSDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*eb9aea5aSDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*eb9aea5aSDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*eb9aea5aSDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*eb9aea5aSDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*eb9aea5aSDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*eb9aea5aSDavid E. O'Brien * SUCH DAMAGE. 26*eb9aea5aSDavid E. O'Brien */ 27*eb9aea5aSDavid E. O'Brien 28*eb9aea5aSDavid E. O'Brien #include <sys/cdefs.h> 29*eb9aea5aSDavid E. O'Brien __FBSDID("$FreeBSD$"); 30*eb9aea5aSDavid E. O'Brien 31*eb9aea5aSDavid E. O'Brien #include <sys/param.h> 32*eb9aea5aSDavid E. O'Brien #include <sys/file.h> 33*eb9aea5aSDavid E. O'Brien #include <sys/systm.h> 34*eb9aea5aSDavid E. O'Brien #include <sys/buf.h> 35*eb9aea5aSDavid E. O'Brien #include <sys/condvar.h> 36*eb9aea5aSDavid E. O'Brien #include <sys/conf.h> 37*eb9aea5aSDavid E. O'Brien #include <sys/fcntl.h> 38*eb9aea5aSDavid E. O'Brien #include <sys/ioccom.h> 39*eb9aea5aSDavid E. O'Brien #include <sys/kernel.h> 40*eb9aea5aSDavid E. O'Brien #include <sys/malloc.h> 41*eb9aea5aSDavid E. O'Brien #include <sys/module.h> 42*eb9aea5aSDavid E. O'Brien #include <sys/mutex.h> 43*eb9aea5aSDavid E. O'Brien #include <sys/poll.h> 44*eb9aea5aSDavid E. O'Brien #include <sys/proc.h> 45*eb9aea5aSDavid E. O'Brien #include <sys/queue.h> 46*eb9aea5aSDavid E. O'Brien #include <sys/syscall.h> 47*eb9aea5aSDavid E. O'Brien #include <sys/sysent.h> 48*eb9aea5aSDavid E. O'Brien #include <sys/sysproto.h> 49*eb9aea5aSDavid E. O'Brien #include <sys/uio.h> 50*eb9aea5aSDavid E. O'Brien 51*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version >= 900041 52*eb9aea5aSDavid E. O'Brien #include <sys/capability.h> 53*eb9aea5aSDavid E. O'Brien #endif 54*eb9aea5aSDavid E. O'Brien 55*eb9aea5aSDavid E. O'Brien #include "filemon.h" 56*eb9aea5aSDavid E. O'Brien 57*eb9aea5aSDavid E. O'Brien #if defined(COMPAT_IA32) || defined(COMPAT_FREEBSD32) || defined(COMPAT_ARCH32) 58*eb9aea5aSDavid E. O'Brien #include <compat/freebsd32/freebsd32_syscall.h> 59*eb9aea5aSDavid E. O'Brien #include <compat/freebsd32/freebsd32_proto.h> 60*eb9aea5aSDavid E. O'Brien 61*eb9aea5aSDavid E. O'Brien extern struct sysentvec ia32_freebsd_sysvec; 62*eb9aea5aSDavid E. O'Brien #endif 63*eb9aea5aSDavid E. O'Brien 64*eb9aea5aSDavid E. O'Brien extern struct sysentvec elf32_freebsd_sysvec; 65*eb9aea5aSDavid E. O'Brien extern struct sysentvec elf64_freebsd_sysvec; 66*eb9aea5aSDavid E. O'Brien 67*eb9aea5aSDavid E. O'Brien static d_close_t filemon_close; 68*eb9aea5aSDavid E. O'Brien static d_ioctl_t filemon_ioctl; 69*eb9aea5aSDavid E. O'Brien static d_open_t filemon_open; 70*eb9aea5aSDavid E. O'Brien static int filemon_unload(void); 71*eb9aea5aSDavid E. O'Brien static void filemon_load(void *); 72*eb9aea5aSDavid E. O'Brien 73*eb9aea5aSDavid E. O'Brien static struct cdevsw filemon_cdevsw = { 74*eb9aea5aSDavid E. O'Brien .d_version = D_VERSION, 75*eb9aea5aSDavid E. O'Brien .d_close = filemon_close, 76*eb9aea5aSDavid E. O'Brien .d_ioctl = filemon_ioctl, 77*eb9aea5aSDavid E. O'Brien .d_open = filemon_open, 78*eb9aea5aSDavid E. O'Brien .d_name = "filemon", 79*eb9aea5aSDavid E. O'Brien }; 80*eb9aea5aSDavid E. O'Brien 81*eb9aea5aSDavid E. O'Brien MALLOC_DECLARE(M_FILEMON); 82*eb9aea5aSDavid E. O'Brien MALLOC_DEFINE(M_FILEMON, "filemon", "File access monitor"); 83*eb9aea5aSDavid E. O'Brien 84*eb9aea5aSDavid E. O'Brien struct filemon { 85*eb9aea5aSDavid E. O'Brien TAILQ_ENTRY(filemon) link; /* Link into the in-use list. */ 86*eb9aea5aSDavid E. O'Brien struct mtx mtx; /* Lock mutex for this filemon. */ 87*eb9aea5aSDavid E. O'Brien struct cv cv; /* Lock condition variable for this 88*eb9aea5aSDavid E. O'Brien filemon. */ 89*eb9aea5aSDavid E. O'Brien struct file *fp; /* Output file pointer. */ 90*eb9aea5aSDavid E. O'Brien struct thread *locker; /* Ptr to the thread locking this 91*eb9aea5aSDavid E. O'Brien filemon. */ 92*eb9aea5aSDavid E. O'Brien pid_t pid; /* The process ID being monitored. */ 93*eb9aea5aSDavid E. O'Brien char fname1[MAXPATHLEN]; /* Temporary filename buffer. */ 94*eb9aea5aSDavid E. O'Brien char fname2[MAXPATHLEN]; /* Temporary filename buffer. */ 95*eb9aea5aSDavid E. O'Brien char msgbufr[1024]; /* Output message buffer. */ 96*eb9aea5aSDavid E. O'Brien }; 97*eb9aea5aSDavid E. O'Brien 98*eb9aea5aSDavid E. O'Brien static TAILQ_HEAD(, filemon) filemons_inuse = TAILQ_HEAD_INITIALIZER(filemons_inuse); 99*eb9aea5aSDavid E. O'Brien static TAILQ_HEAD(, filemon) filemons_free = TAILQ_HEAD_INITIALIZER(filemons_free); 100*eb9aea5aSDavid E. O'Brien static int n_readers = 0; 101*eb9aea5aSDavid E. O'Brien static struct mtx access_mtx; 102*eb9aea5aSDavid E. O'Brien static struct cv access_cv; 103*eb9aea5aSDavid E. O'Brien static struct thread *access_owner = NULL; 104*eb9aea5aSDavid E. O'Brien static struct thread *access_requester = NULL; 105*eb9aea5aSDavid E. O'Brien 106*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 107*eb9aea5aSDavid E. O'Brien static struct clonedevs *filemon_clones; 108*eb9aea5aSDavid E. O'Brien static eventhandler_tag eh_tag; 109*eb9aea5aSDavid E. O'Brien #else 110*eb9aea5aSDavid E. O'Brien static struct cdev *filemon_dev; 111*eb9aea5aSDavid E. O'Brien #endif 112*eb9aea5aSDavid E. O'Brien 113*eb9aea5aSDavid E. O'Brien #include "filemon_lock.c" 114*eb9aea5aSDavid E. O'Brien #include "filemon_wrapper.c" 115*eb9aea5aSDavid E. O'Brien 116*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 117*eb9aea5aSDavid E. O'Brien static void 118*eb9aea5aSDavid E. O'Brien filemon_clone(void *arg, struct ucred *cred, char *name, int namelen, 119*eb9aea5aSDavid E. O'Brien struct cdev **dev) 120*eb9aea5aSDavid E. O'Brien { 121*eb9aea5aSDavid E. O'Brien int u = -1; 122*eb9aea5aSDavid E. O'Brien size_t len; 123*eb9aea5aSDavid E. O'Brien 124*eb9aea5aSDavid E. O'Brien if (*dev != NULL) 125*eb9aea5aSDavid E. O'Brien return; 126*eb9aea5aSDavid E. O'Brien 127*eb9aea5aSDavid E. O'Brien len = strlen(name); 128*eb9aea5aSDavid E. O'Brien 129*eb9aea5aSDavid E. O'Brien if (len != 7) 130*eb9aea5aSDavid E. O'Brien return; 131*eb9aea5aSDavid E. O'Brien 132*eb9aea5aSDavid E. O'Brien if (bcmp(name,"filemon", 7) != 0) 133*eb9aea5aSDavid E. O'Brien return; 134*eb9aea5aSDavid E. O'Brien 135*eb9aea5aSDavid E. O'Brien /* Clone the device to the new minor number. */ 136*eb9aea5aSDavid E. O'Brien if (clone_create(&filemon_clones, &filemon_cdevsw, &u, dev, 0) != 0) 137*eb9aea5aSDavid E. O'Brien /* Create the /dev/filemonNN entry. */ 138*eb9aea5aSDavid E. O'Brien *dev = make_dev_cred(&filemon_cdevsw, u, cred, UID_ROOT, 139*eb9aea5aSDavid E. O'Brien GID_WHEEL, 0666, "filemon%d", u); 140*eb9aea5aSDavid E. O'Brien if (*dev != NULL) { 141*eb9aea5aSDavid E. O'Brien dev_ref(*dev); 142*eb9aea5aSDavid E. O'Brien (*dev)->si_flags |= SI_CHEAPCLONE; 143*eb9aea5aSDavid E. O'Brien } 144*eb9aea5aSDavid E. O'Brien } 145*eb9aea5aSDavid E. O'Brien #endif 146*eb9aea5aSDavid E. O'Brien 147*eb9aea5aSDavid E. O'Brien static void 148*eb9aea5aSDavid E. O'Brien filemon_dtr(void *data) 149*eb9aea5aSDavid E. O'Brien { 150*eb9aea5aSDavid E. O'Brien struct filemon *filemon = data; 151*eb9aea5aSDavid E. O'Brien 152*eb9aea5aSDavid E. O'Brien if (filemon != NULL) { 153*eb9aea5aSDavid E. O'Brien struct file *fp = filemon->fp; 154*eb9aea5aSDavid E. O'Brien 155*eb9aea5aSDavid E. O'Brien /* Get exclusive write access. */ 156*eb9aea5aSDavid E. O'Brien filemon_lock_write(); 157*eb9aea5aSDavid E. O'Brien 158*eb9aea5aSDavid E. O'Brien /* Remove from the in-use list. */ 159*eb9aea5aSDavid E. O'Brien TAILQ_REMOVE(&filemons_inuse, filemon, link); 160*eb9aea5aSDavid E. O'Brien 161*eb9aea5aSDavid E. O'Brien filemon->fp = NULL; 162*eb9aea5aSDavid E. O'Brien filemon->pid = -1; 163*eb9aea5aSDavid E. O'Brien 164*eb9aea5aSDavid E. O'Brien /* Add to the free list. */ 165*eb9aea5aSDavid E. O'Brien TAILQ_INSERT_TAIL(&filemons_free, filemon, link); 166*eb9aea5aSDavid E. O'Brien 167*eb9aea5aSDavid E. O'Brien /* Give up write access. */ 168*eb9aea5aSDavid E. O'Brien filemon_unlock_write(); 169*eb9aea5aSDavid E. O'Brien 170*eb9aea5aSDavid E. O'Brien if (fp != NULL) 171*eb9aea5aSDavid E. O'Brien fdrop(fp, curthread); 172*eb9aea5aSDavid E. O'Brien } 173*eb9aea5aSDavid E. O'Brien } 174*eb9aea5aSDavid E. O'Brien 175*eb9aea5aSDavid E. O'Brien static int 176*eb9aea5aSDavid E. O'Brien filemon_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag __unused, 177*eb9aea5aSDavid E. O'Brien struct thread *td) 178*eb9aea5aSDavid E. O'Brien { 179*eb9aea5aSDavid E. O'Brien int error = 0; 180*eb9aea5aSDavid E. O'Brien struct filemon *filemon; 181*eb9aea5aSDavid E. O'Brien 182*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 183*eb9aea5aSDavid E. O'Brien filemon = dev->si_drv1; 184*eb9aea5aSDavid E. O'Brien #else 185*eb9aea5aSDavid E. O'Brien devfs_get_cdevpriv((void **) &filemon); 186*eb9aea5aSDavid E. O'Brien #endif 187*eb9aea5aSDavid E. O'Brien 188*eb9aea5aSDavid E. O'Brien switch (cmd) { 189*eb9aea5aSDavid E. O'Brien /* Set the output file descriptor. */ 190*eb9aea5aSDavid E. O'Brien case FILEMON_SET_FD: 191*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 900041 192*eb9aea5aSDavid E. O'Brien #define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), (a3)) 193*eb9aea5aSDavid E. O'Brien #else 194*eb9aea5aSDavid E. O'Brien #define FGET_WRITE(a1, a2, a3) fget_write((a1), (a2), CAP_WRITE | CAP_SEEK, (a3)) 195*eb9aea5aSDavid E. O'Brien #endif 196*eb9aea5aSDavid E. O'Brien if ((error = FGET_WRITE(td, *(int *)data, &filemon->fp)) == 0) 197*eb9aea5aSDavid E. O'Brien /* Write the file header. */ 198*eb9aea5aSDavid E. O'Brien filemon_comment(filemon); 199*eb9aea5aSDavid E. O'Brien break; 200*eb9aea5aSDavid E. O'Brien 201*eb9aea5aSDavid E. O'Brien /* Set the monitored process ID. */ 202*eb9aea5aSDavid E. O'Brien case FILEMON_SET_PID: 203*eb9aea5aSDavid E. O'Brien filemon->pid = *((pid_t *) data); 204*eb9aea5aSDavid E. O'Brien break; 205*eb9aea5aSDavid E. O'Brien 206*eb9aea5aSDavid E. O'Brien default: 207*eb9aea5aSDavid E. O'Brien error = EINVAL; 208*eb9aea5aSDavid E. O'Brien break; 209*eb9aea5aSDavid E. O'Brien } 210*eb9aea5aSDavid E. O'Brien 211*eb9aea5aSDavid E. O'Brien return (error); 212*eb9aea5aSDavid E. O'Brien } 213*eb9aea5aSDavid E. O'Brien 214*eb9aea5aSDavid E. O'Brien static int 215*eb9aea5aSDavid E. O'Brien filemon_open(struct cdev *dev, int oflags __unused, int devtype __unused, 216*eb9aea5aSDavid E. O'Brien struct thread *td __unused) 217*eb9aea5aSDavid E. O'Brien { 218*eb9aea5aSDavid E. O'Brien struct filemon *filemon; 219*eb9aea5aSDavid E. O'Brien 220*eb9aea5aSDavid E. O'Brien /* Get exclusive write access. */ 221*eb9aea5aSDavid E. O'Brien filemon_lock_write(); 222*eb9aea5aSDavid E. O'Brien 223*eb9aea5aSDavid E. O'Brien if ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) 224*eb9aea5aSDavid E. O'Brien TAILQ_REMOVE(&filemons_free, filemon, link); 225*eb9aea5aSDavid E. O'Brien 226*eb9aea5aSDavid E. O'Brien /* Give up write access. */ 227*eb9aea5aSDavid E. O'Brien filemon_unlock_write(); 228*eb9aea5aSDavid E. O'Brien 229*eb9aea5aSDavid E. O'Brien if (filemon == NULL) { 230*eb9aea5aSDavid E. O'Brien filemon = malloc(sizeof(struct filemon), M_FILEMON, 231*eb9aea5aSDavid E. O'Brien M_WAITOK | M_ZERO); 232*eb9aea5aSDavid E. O'Brien 233*eb9aea5aSDavid E. O'Brien filemon->fp = NULL; 234*eb9aea5aSDavid E. O'Brien 235*eb9aea5aSDavid E. O'Brien mtx_init(&filemon->mtx, "filemon", "filemon", MTX_DEF); 236*eb9aea5aSDavid E. O'Brien cv_init(&filemon->cv, "filemon"); 237*eb9aea5aSDavid E. O'Brien } 238*eb9aea5aSDavid E. O'Brien 239*eb9aea5aSDavid E. O'Brien filemon->pid = curproc->p_pid; 240*eb9aea5aSDavid E. O'Brien 241*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 242*eb9aea5aSDavid E. O'Brien dev->si_drv1 = filemon; 243*eb9aea5aSDavid E. O'Brien #else 244*eb9aea5aSDavid E. O'Brien devfs_set_cdevpriv(filemon, filemon_dtr); 245*eb9aea5aSDavid E. O'Brien #endif 246*eb9aea5aSDavid E. O'Brien 247*eb9aea5aSDavid E. O'Brien /* Get exclusive write access. */ 248*eb9aea5aSDavid E. O'Brien filemon_lock_write(); 249*eb9aea5aSDavid E. O'Brien 250*eb9aea5aSDavid E. O'Brien /* Add to the in-use list. */ 251*eb9aea5aSDavid E. O'Brien TAILQ_INSERT_TAIL(&filemons_inuse, filemon, link); 252*eb9aea5aSDavid E. O'Brien 253*eb9aea5aSDavid E. O'Brien /* Give up write access. */ 254*eb9aea5aSDavid E. O'Brien filemon_unlock_write(); 255*eb9aea5aSDavid E. O'Brien 256*eb9aea5aSDavid E. O'Brien return (0); 257*eb9aea5aSDavid E. O'Brien } 258*eb9aea5aSDavid E. O'Brien 259*eb9aea5aSDavid E. O'Brien static int 260*eb9aea5aSDavid E. O'Brien filemon_close(struct cdev *dev __unused, int flag __unused, int fmt __unused, 261*eb9aea5aSDavid E. O'Brien struct thread *td __unused) 262*eb9aea5aSDavid E. O'Brien { 263*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 264*eb9aea5aSDavid E. O'Brien filemon_dtr(dev->si_drv1); 265*eb9aea5aSDavid E. O'Brien 266*eb9aea5aSDavid E. O'Brien dev->si_drv1 = NULL; 267*eb9aea5aSDavid E. O'Brien 268*eb9aea5aSDavid E. O'Brien /* Schedule this cloned device to be destroyed. */ 269*eb9aea5aSDavid E. O'Brien destroy_dev_sched(dev); 270*eb9aea5aSDavid E. O'Brien #endif 271*eb9aea5aSDavid E. O'Brien 272*eb9aea5aSDavid E. O'Brien return (0); 273*eb9aea5aSDavid E. O'Brien } 274*eb9aea5aSDavid E. O'Brien 275*eb9aea5aSDavid E. O'Brien static void 276*eb9aea5aSDavid E. O'Brien filemon_load(void *dummy __unused) 277*eb9aea5aSDavid E. O'Brien { 278*eb9aea5aSDavid E. O'Brien mtx_init(&access_mtx, "filemon", "filemon", MTX_DEF); 279*eb9aea5aSDavid E. O'Brien cv_init(&access_cv, "filemon"); 280*eb9aea5aSDavid E. O'Brien 281*eb9aea5aSDavid E. O'Brien /* Install the syscall wrappers. */ 282*eb9aea5aSDavid E. O'Brien filemon_wrapper_install(); 283*eb9aea5aSDavid E. O'Brien 284*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 285*eb9aea5aSDavid E. O'Brien /* Enable device cloning. */ 286*eb9aea5aSDavid E. O'Brien clone_setup(&filemon_clones); 287*eb9aea5aSDavid E. O'Brien 288*eb9aea5aSDavid E. O'Brien /* Setup device cloning events. */ 289*eb9aea5aSDavid E. O'Brien eh_tag = EVENTHANDLER_REGISTER(dev_clone, filemon_clone, 0, 1000); 290*eb9aea5aSDavid E. O'Brien #else 291*eb9aea5aSDavid E. O'Brien filemon_dev = make_dev(&filemon_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, 292*eb9aea5aSDavid E. O'Brien "filemon"); 293*eb9aea5aSDavid E. O'Brien #endif 294*eb9aea5aSDavid E. O'Brien } 295*eb9aea5aSDavid E. O'Brien 296*eb9aea5aSDavid E. O'Brien static int 297*eb9aea5aSDavid E. O'Brien filemon_unload(void) 298*eb9aea5aSDavid E. O'Brien { 299*eb9aea5aSDavid E. O'Brien struct filemon *filemon; 300*eb9aea5aSDavid E. O'Brien int error = 0; 301*eb9aea5aSDavid E. O'Brien 302*eb9aea5aSDavid E. O'Brien /* Get exclusive write access. */ 303*eb9aea5aSDavid E. O'Brien filemon_lock_write(); 304*eb9aea5aSDavid E. O'Brien 305*eb9aea5aSDavid E. O'Brien if (TAILQ_FIRST(&filemons_inuse) != NULL) 306*eb9aea5aSDavid E. O'Brien error = EBUSY; 307*eb9aea5aSDavid E. O'Brien else { 308*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version >= 701000 309*eb9aea5aSDavid E. O'Brien destroy_dev(filemon_dev); 310*eb9aea5aSDavid E. O'Brien #endif 311*eb9aea5aSDavid E. O'Brien 312*eb9aea5aSDavid E. O'Brien /* Deinstall the syscall wrappers. */ 313*eb9aea5aSDavid E. O'Brien filemon_wrapper_deinstall(); 314*eb9aea5aSDavid E. O'Brien } 315*eb9aea5aSDavid E. O'Brien 316*eb9aea5aSDavid E. O'Brien /* Give up write access. */ 317*eb9aea5aSDavid E. O'Brien filemon_unlock_write(); 318*eb9aea5aSDavid E. O'Brien 319*eb9aea5aSDavid E. O'Brien if (error == 0) { 320*eb9aea5aSDavid E. O'Brien #if __FreeBSD_version < 701000 321*eb9aea5aSDavid E. O'Brien /* 322*eb9aea5aSDavid E. O'Brien * Check if there is still an event handler callback registered. 323*eb9aea5aSDavid E. O'Brien */ 324*eb9aea5aSDavid E. O'Brien if (eh_tag != 0) { 325*eb9aea5aSDavid E. O'Brien /* De-register the device cloning event handler. */ 326*eb9aea5aSDavid E. O'Brien EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 327*eb9aea5aSDavid E. O'Brien eh_tag = 0; 328*eb9aea5aSDavid E. O'Brien 329*eb9aea5aSDavid E. O'Brien /* Stop device cloning. */ 330*eb9aea5aSDavid E. O'Brien clone_cleanup(&filemon_clones); 331*eb9aea5aSDavid E. O'Brien } 332*eb9aea5aSDavid E. O'Brien #endif 333*eb9aea5aSDavid E. O'Brien /* free() filemon structs free list. */ 334*eb9aea5aSDavid E. O'Brien filemon_lock_write(); 335*eb9aea5aSDavid E. O'Brien while ((filemon = TAILQ_FIRST(&filemons_free)) != NULL) { 336*eb9aea5aSDavid E. O'Brien TAILQ_REMOVE(&filemons_free, filemon, link); 337*eb9aea5aSDavid E. O'Brien mtx_destroy(&filemon->mtx); 338*eb9aea5aSDavid E. O'Brien cv_destroy(&filemon->cv); 339*eb9aea5aSDavid E. O'Brien free(filemon, M_FILEMON); 340*eb9aea5aSDavid E. O'Brien } 341*eb9aea5aSDavid E. O'Brien filemon_unlock_write(); 342*eb9aea5aSDavid E. O'Brien 343*eb9aea5aSDavid E. O'Brien mtx_destroy(&access_mtx); 344*eb9aea5aSDavid E. O'Brien cv_destroy(&access_cv); 345*eb9aea5aSDavid E. O'Brien } 346*eb9aea5aSDavid E. O'Brien 347*eb9aea5aSDavid E. O'Brien return (error); 348*eb9aea5aSDavid E. O'Brien } 349*eb9aea5aSDavid E. O'Brien 350*eb9aea5aSDavid E. O'Brien static int 351*eb9aea5aSDavid E. O'Brien filemon_modevent(module_t mod __unused, int type, void *data) 352*eb9aea5aSDavid E. O'Brien { 353*eb9aea5aSDavid E. O'Brien int error = 0; 354*eb9aea5aSDavid E. O'Brien 355*eb9aea5aSDavid E. O'Brien switch (type) { 356*eb9aea5aSDavid E. O'Brien case MOD_LOAD: 357*eb9aea5aSDavid E. O'Brien filemon_load(data); 358*eb9aea5aSDavid E. O'Brien break; 359*eb9aea5aSDavid E. O'Brien 360*eb9aea5aSDavid E. O'Brien case MOD_UNLOAD: 361*eb9aea5aSDavid E. O'Brien error = filemon_unload(); 362*eb9aea5aSDavid E. O'Brien break; 363*eb9aea5aSDavid E. O'Brien 364*eb9aea5aSDavid E. O'Brien case MOD_SHUTDOWN: 365*eb9aea5aSDavid E. O'Brien break; 366*eb9aea5aSDavid E. O'Brien 367*eb9aea5aSDavid E. O'Brien default: 368*eb9aea5aSDavid E. O'Brien error = EOPNOTSUPP; 369*eb9aea5aSDavid E. O'Brien break; 370*eb9aea5aSDavid E. O'Brien 371*eb9aea5aSDavid E. O'Brien } 372*eb9aea5aSDavid E. O'Brien 373*eb9aea5aSDavid E. O'Brien return (error); 374*eb9aea5aSDavid E. O'Brien } 375*eb9aea5aSDavid E. O'Brien 376*eb9aea5aSDavid E. O'Brien DEV_MODULE(filemon, filemon_modevent, NULL); 377*eb9aea5aSDavid E. O'Brien MODULE_VERSION(filemon, 1); 378