The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/filemon/filemon.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 6affd994cd69938e5b41e719303822e6


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.