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/fs/devfs/devfs_rule.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) 2002 Dima Dorfman.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: releng/5.0/sys/fs/devfs/devfs_rule.c 105212 2002-10-16 08:04:11Z phk $
   27  */
   28 
   29 /*
   30  * DEVFS ruleset implementation.
   31  *
   32  * A note on terminology: To "run" a rule on a dirent is to take the
   33  * prescribed action; to "apply" a rule is to check whether it matches
   34  * a dirent and run if if it does.
   35  *
   36  * A note on locking: Only foreign entry points (non-static functions)
   37  * should deal with locking.  Everything else assumes we already hold
   38  * the required kind of lock.
   39  *
   40  * A note on namespace: devfs_rules_* are the non-static functions for
   41  * the entire "ruleset" subsystem, devfs_rule_* are the static
   42  * functions that operate on rules, and devfs_ruleset_* are the static
   43  * functions that operate on rulesets.  The line between the last two
   44  * isn't always clear, but the guideline is still useful.
   45  *
   46  * A note on "special" identifiers: Ruleset 0 is the NULL, or empty,
   47  * ruleset; it cannot be deleted or changed in any way.  This may be
   48  * assumed inside the code; e.g., a ruleset of 0 may be interpeted to
   49  * mean "no ruleset".  The interpretation of rule 0 is
   50  * command-dependent, but in no case is there a real rule with number
   51  * 0.
   52  *
   53  * A note on errno codes: To make it easier for the userland to tell
   54  * what went wrong, we sometimes use errno codes that are not entirely
   55  * appropriate for the error but that would be less ambiguous than the
   56  * appropriate "generic" code.  For example, when we can't find a
   57  * ruleset, we return ESRCH instead of ENOENT (except in
   58  * DEVFSIO_{R,S}GETNEXT, where a nonexistent ruleset means "end of
   59  * list", and the userland expects ENOENT to be this indicator); this
   60  * way, when an operation fails, it's clear that what couldn't be
   61  * found is a ruleset and not a rule (well, it's clear to those who
   62  * know the convention).
   63  */
   64 
   65 #include "opt_devfs.h"
   66 #ifndef NODEVFS
   67 
   68 #include <sys/param.h>
   69 #include <sys/systm.h>
   70 #include <sys/conf.h>
   71 #include <sys/kernel.h>
   72 #include <sys/malloc.h>
   73 #include <sys/dirent.h>
   74 #include <sys/vnode.h>
   75 #include <sys/mount.h>
   76 #include <sys/ioccom.h>
   77 
   78 #include <fs/devfs/devfs.h>
   79 
   80 
   81 /*
   82  * Kernel version of devfs_rule.
   83  */
   84 struct devfs_krule {
   85         SLIST_ENTRY(devfs_krule) dk_list;
   86         struct devfs_ruleset *dk_ruleset;
   87         struct devfs_rule dk_rule;
   88 };
   89 
   90 /*
   91  * Structure to describe a ruleset.
   92  */
   93 struct devfs_ruleset {
   94         SLIST_ENTRY(devfs_ruleset) ds_list;
   95         devfs_rsnum ds_number;
   96         SLIST_HEAD(, devfs_krule) ds_rules;
   97         int     ds_refcount;
   98         int     ds_flags;
   99 #define DS_IMMUTABLE    0x001
  100         int     ds_running;
  101 };
  102 
  103 static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
  104 
  105 static void devfs_rule_applyde(struct devfs_krule *dk,struct devfs_dirent *de);
  106 static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
  107                 struct devfs_dirent *de);
  108 static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
  109 static int  devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
  110 static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
  111 static int  devfs_rule_delete(struct devfs_krule **dkp);
  112 static dev_t devfs_rule_getdev(struct devfs_dirent *de);
  113 static int  devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
  114 static int  devfs_rule_insert(struct devfs_rule *dr);
  115 static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
  116 static int  devfs_rule_matchpath(struct devfs_krule *dk,
  117                 struct devfs_dirent *de);
  118 static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de);
  119 
  120 static void devfs_ruleset_applyde(struct devfs_ruleset *ds,
  121                 struct devfs_dirent *de);
  122 static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
  123                 struct devfs_mount *dm);
  124 static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
  125 static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum);
  126 static void devfs_ruleset_destroy(struct devfs_ruleset **dsp);
  127 static void devfs_ruleset_reap(struct devfs_ruleset **dsp);
  128 static int  devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
  129 
  130 static SLIST_HEAD(, devfs_ruleset) devfs_rulesets;
  131 
  132 /*
  133  * Called to apply the proper rules for de before the latter can be
  134  * exposed to the userland.  This should be called with an exclusive
  135  * lock on dm in case we need to run anything.
  136  */
  137 void
  138 devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
  139 {
  140         struct devfs_ruleset *ds;
  141 
  142         ds = devfs_ruleset_bynum(dm->dm_ruleset);
  143         KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
  144         devfs_ruleset_applyde(ds, de);
  145 }
  146 
  147 /*
  148  * Rule subsystem SYSINIT hook.
  149  */
  150 void
  151 devfs_rules_init(void)
  152 {
  153         struct devfs_ruleset *ds;
  154 
  155         SLIST_INIT(&devfs_rulesets);
  156 
  157         ds = devfs_ruleset_create(0);
  158         ds->ds_flags |= DS_IMMUTABLE;
  159         ds->ds_refcount = 1;            /* Prevent reaping. */
  160 }
  161 
  162 /*
  163  * Rule subsystem ioctl hook.
  164  */
  165 int
  166 devfs_rules_ioctl(struct mount *mp, u_long cmd, caddr_t data, struct thread *td)
  167 {
  168         struct devfs_mount *dm = VFSTODEVFS(mp);
  169         struct devfs_ruleset *ds;
  170         struct devfs_krule *dk;
  171         struct devfs_rule *dr;
  172         devfs_rsnum rsnum;
  173         devfs_rnum rnum;
  174         devfs_rid rid;
  175         int error;
  176 
  177         /*
  178          * XXX: This returns an error regardless of whether we
  179          * actually support the cmd or not.
  180          */
  181         error = suser(td);
  182         if (error != 0)
  183                 return (error);
  184 
  185         lockmgr(&dm->dm_lock, LK_SHARED, 0, td);
  186 
  187         switch (cmd) {
  188         case DEVFSIO_RADD:
  189                 dr = (struct devfs_rule *)data;
  190                 error = devfs_rule_input(dr, dm);
  191                 if (error != 0)
  192                         goto out;
  193                 dk = devfs_rule_byid(dr->dr_id);
  194                 if (dk != NULL) {
  195                         error = EEXIST;
  196                         goto out;
  197                 }
  198                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  199                 error = devfs_rule_insert(dr);
  200                 break;
  201         case DEVFSIO_RAPPLY:
  202                 dr = (struct devfs_rule *)data;
  203                 error = devfs_rule_input(dr, dm);
  204                 if (error != 0)
  205                         goto out;
  206 
  207                 /*
  208                  * This is one of many possible hackish
  209                  * implementations.  The primary contender is an
  210                  * implementation where the rule we read in is
  211                  * temporarily inserted into some ruleset, perhaps
  212                  * with a hypothetical DRO_NOAUTO flag so that it
  213                  * doesn't get used where it isn't intended, and
  214                  * applied in the normal way.  This can be done in the
  215                  * userland (DEVFSIO_ADD, DEVFSIO_APPLYID,
  216                  * DEVFSIO_DEL) or in the kernel; either way it breaks
  217                  * some corner case assumptions in other parts of the
  218                  * code (not that this implementation doesn't do
  219                  * that).
  220                  */
  221                 if (dr->dr_iacts & DRA_INCSET &&
  222                     devfs_ruleset_bynum(dr->dr_incset) == NULL) {
  223                         error = ESRCH;
  224                         goto out;
  225                 }
  226                 dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO);
  227                 memcpy(&dk->dk_rule, dr, sizeof(*dr));
  228                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  229                 devfs_rule_applydm(dk, dm);
  230                 lockmgr(&dm->dm_lock, LK_DOWNGRADE, 0, td);
  231                 free(dk, M_TEMP);
  232                 error = 0;
  233                 break;
  234         case DEVFSIO_RAPPLYID:
  235                 rid = *(devfs_rid *)data;
  236                 rid = devfs_rid_input(rid, dm);
  237                 dk = devfs_rule_byid(rid);
  238                 if (dk == NULL) {
  239                         error = ENOENT;
  240                         goto out;
  241                 }
  242                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  243                 devfs_rule_applydm(dk, dm);
  244                 error = 0;
  245                 break;
  246         case DEVFSIO_RDEL:
  247                 rid = *(devfs_rid *)data;
  248                 rid = devfs_rid_input(rid, dm);
  249                 dk = devfs_rule_byid(rid);
  250                 if (dk == NULL) {
  251                         error = ENOENT;
  252                         goto out;
  253                 }
  254                 ds = dk->dk_ruleset;
  255                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  256                 error = devfs_rule_delete(&dk);
  257                 devfs_ruleset_reap(&ds);
  258                 break;
  259         case DEVFSIO_RGETNEXT:
  260                 dr = (struct devfs_rule *)data;
  261                 error = devfs_rule_input(dr, dm);
  262                 if (error != 0)
  263                         goto out;
  264                 /*
  265                  * We can't use devfs_rule_byid() here since that
  266                  * requires the rule specified to exist, but we want
  267                  * getnext(N) to work whether there is a rule N or not
  268                  * (specifically, getnext(0) must work, but we should
  269                  * never have a rule 0 since the add command
  270                  * interprets 0 to mean "auto-number").
  271                  */
  272                 ds = devfs_ruleset_bynum(rid2rsn(dr->dr_id));
  273                 if (ds == NULL) {
  274                         error = ENOENT;
  275                         goto out;
  276                 }
  277                 rnum = rid2rn(dr->dr_id);
  278                 SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  279                         if (rid2rn(dk->dk_rule.dr_id) > rnum)
  280                                 break;
  281                 }
  282                 if (dk == NULL) {
  283                         error = ENOENT;
  284                         goto out;
  285                 }
  286                 memcpy(dr, &dk->dk_rule, sizeof(*dr));
  287                 error = 0;
  288                 break;
  289         case DEVFSIO_SUSE:
  290                 rsnum = *(devfs_rsnum *)data;
  291                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  292                 error = devfs_ruleset_use(rsnum, dm);
  293                 break;
  294         case DEVFSIO_SAPPLY:
  295                 rsnum = *(devfs_rsnum *)data;
  296                 rsnum = rid2rsn(devfs_rid_input(mkrid(rsnum, 0), dm));
  297                 ds = devfs_ruleset_bynum(rsnum);
  298                 if (ds == NULL) {
  299                         error = ESRCH;
  300                         goto out;
  301                 }
  302                 lockmgr(&dm->dm_lock, LK_UPGRADE, 0, td);
  303                 devfs_ruleset_applydm(ds, dm);
  304                 error = 0;
  305                 break;
  306         case DEVFSIO_SGETNEXT:
  307                 rsnum = *(devfs_rsnum *)data;
  308                 SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
  309                         if (ds->ds_number > rsnum)
  310                                 break;
  311                 }
  312                 if (ds == NULL)
  313                         error = ENOENT;
  314                 else {
  315                         *(devfs_rsnum *)data = ds->ds_number;
  316                         error = 0;
  317                 }
  318                 break;
  319         default:
  320                 error = ENOIOCTL;
  321                 break;
  322         }
  323 
  324 out:
  325         lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
  326         return (error);
  327 }
  328 
  329 /*
  330  * Called to initialize dm_ruleset when there is a new mount-point.
  331  */
  332 void
  333 devfs_rules_newmount(struct devfs_mount *dm, struct thread *td)
  334 {
  335         struct devfs_ruleset *ds;
  336 
  337         lockmgr(&dm->dm_lock, LK_EXCLUSIVE, 0, td);
  338         /*
  339          * We can't use devfs_ruleset_use() since it will try to
  340          * decrement the refcount for the old ruleset, and there is no
  341          * old ruleset.  Making some value of ds_ruleset "special" to
  342          * mean "don't decrement refcount" is uglier than this.
  343          */
  344         ds = devfs_ruleset_bynum(0);
  345         KASSERT(ds != NULL, ("no ruleset 0"));
  346         ++ds->ds_refcount;
  347         dm->dm_ruleset = 0;
  348         lockmgr(&dm->dm_lock, LK_RELEASE, 0, td);
  349 }
  350 
  351 /*
  352  * Adjust the rule identifier to use the ruleset of dm if one isn't
  353  * explicitly specified.
  354  *
  355  * Note that after this operation, rid2rsn(rid) might still be 0, and
  356  * that's okay; ruleset 0 is a valid ruleset, but when it's read in
  357  * from the userland, it means "current ruleset for this mount-point".
  358  */
  359 static devfs_rid
  360 devfs_rid_input(devfs_rid rid, struct devfs_mount *dm)
  361 {
  362 
  363         if (rid2rsn(rid) == 0)
  364                 return (mkrid(dm->dm_ruleset, rid2rn(rid)));
  365         else
  366                 return (rid);
  367 }
  368 
  369 /*
  370  * Apply dk to de.
  371  */
  372 static void
  373 devfs_rule_applyde(struct devfs_krule *dk, struct devfs_dirent *de)
  374 {
  375 
  376         if (devfs_rule_match(dk, de))
  377                 devfs_rule_run(dk, de);
  378 }
  379 
  380 /*
  381  * Apply dk to de and everything under de.
  382  *
  383  * XXX: This method needs a function call for every nested
  384  * subdirectory in a devfs mount.  If we plan to have many of these,
  385  * we might eventually run out of kernel stack space.
  386  */
  387 static void
  388 devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
  389 {
  390         struct devfs_dirent *de2;
  391 
  392         /* XXX: Should we apply to ourselves first or last?  Does it matter? */
  393         TAILQ_FOREACH(de2, &de->de_dlist, de_list) {
  394                 devfs_rule_applyde_recursive(dk, de2);
  395         }
  396         devfs_rule_applyde(dk, de);
  397 }
  398 
  399 /*
  400  * Apply dk to all entires in dm.
  401  */
  402 static void
  403 devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm)
  404 {
  405 
  406         devfs_rule_applyde_recursive(dk, dm->dm_basedir);
  407 }
  408 
  409 /*
  410  * Automatically select a number for a new rule in ds, and write the
  411  * result into rnump.
  412  */
  413 static int
  414 devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnump)
  415 {
  416         struct devfs_krule *dk;
  417 
  418         /* Find the last rule. */
  419         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  420                 if (SLIST_NEXT(dk, dk_list) == NULL)
  421                         break;
  422         }
  423         if (dk == NULL)
  424                 *rnump = 100;
  425         else {
  426                 *rnump = rid2rn(dk->dk_rule.dr_id) + 100;
  427                 /* Detect overflow. */
  428                 if (*rnump < rid2rn(dk->dk_rule.dr_id))
  429                         return (ERANGE);
  430         }
  431         KASSERT(devfs_rule_byid(mkrid(ds->ds_number, *rnump)) == NULL,
  432             ("autonumbering resulted in an already existing rule"));
  433         return (0);
  434 }
  435 
  436 /*
  437  * Find a krule by id.
  438  */
  439 static struct devfs_krule *
  440 devfs_rule_byid(devfs_rid rid)
  441 {
  442         struct devfs_ruleset *ds;
  443         struct devfs_krule *dk;
  444         devfs_rnum rn;
  445 
  446         rn = rid2rn(rid);
  447         ds = devfs_ruleset_bynum(rid2rsn(rid));
  448         if (ds == NULL)
  449                 return (NULL);
  450         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  451                 if (rid2rn(dk->dk_rule.dr_id) == rn)
  452                         return (dk);
  453                 else if (rid2rn(dk->dk_rule.dr_id) > rn)
  454                         break;
  455         }
  456         return (NULL);
  457 }
  458 
  459 /*
  460  * Remove dkp from any lists it may be on and remove memory associated
  461  * with it.
  462  */
  463 static int
  464 devfs_rule_delete(struct devfs_krule **dkp)
  465 {
  466         struct devfs_krule *dk = *dkp;
  467         struct devfs_ruleset *ds;
  468 
  469         if (dk->dk_rule.dr_iacts & DRA_INCSET) {
  470                 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  471                 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  472                 --ds->ds_refcount;
  473                 devfs_ruleset_reap(&ds);
  474         }
  475         SLIST_REMOVE(&dk->dk_ruleset->ds_rules, dk, devfs_krule, dk_list);
  476         free(dk, M_DEVFS);
  477         *dkp = NULL;
  478         return (0);
  479 }
  480 
  481 /*
  482  * Get a dev_t corresponding to de so we can try to match rules based
  483  * on it.  If this routine returns NULL, there is no dev_t associated
  484  * with the dirent (symlinks and directories don't have dev_ts), and
  485  * the caller should assume that any critera dependent on a dev_t
  486  * don't match.
  487  */
  488 static dev_t
  489 devfs_rule_getdev(struct devfs_dirent *de)
  490 {
  491         dev_t *devp, dev;
  492 
  493         devp = devfs_itod(de->de_inode);
  494         if (devp != NULL)
  495                 dev = *devp;
  496         else
  497                 dev = NULL;
  498         /* If we think this dirent should have a dev_t, alert the user. */
  499         if (dev == NULL && de->de_dirent->d_type != DT_LNK &&
  500             de->de_dirent->d_type != DT_DIR)
  501                 printf("Warning: no dev_t for %s\n", de->de_dirent->d_name);
  502         return (dev);
  503 }
  504 
  505 /*
  506  * Do what we need to do to a rule that we just loaded from the
  507  * userland.  In particular, we need to check the magic, and adjust
  508  * the ruleset appropriate if desired.
  509  */
  510 static int
  511 devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm)
  512 {
  513 
  514         if (dr->dr_magic != DEVFS_MAGIC)
  515                 return (ERPCMISMATCH);
  516         dr->dr_id = devfs_rid_input(dr->dr_id, dm);
  517         return (0);
  518 }
  519 
  520 /*
  521  * Import dr into the appropriate place in the kernel (i.e., make a
  522  * krule).  The value of dr is copied, so the pointer may be destroyed
  523  * after this call completes.
  524  */
  525 static int
  526 devfs_rule_insert(struct devfs_rule *dr)
  527 {
  528         struct devfs_ruleset *ds, *dsi;
  529         struct devfs_krule *k1, *k2;
  530         struct devfs_krule *dk;
  531         devfs_rsnum rsnum;
  532         devfs_rnum dkrn;
  533         int error;
  534 
  535         /*
  536          * This stuff seems out of place here, but we want to do it as
  537          * soon as possible so that if it fails, we don't have to roll
  538          * back any changes we already made (e.g., ruleset creation).
  539          */
  540         if (dr->dr_iacts & DRA_INCSET) {
  541                 dsi = devfs_ruleset_bynum(dr->dr_incset);
  542                 if (dsi == NULL)
  543                         return (ESRCH);
  544         } else
  545                 dsi = NULL;
  546 
  547         rsnum = rid2rsn(dr->dr_id);
  548         ds = devfs_ruleset_bynum(rsnum);
  549         if (ds == NULL)
  550                 ds = devfs_ruleset_create(rsnum);
  551         if (ds->ds_flags & DS_IMMUTABLE)
  552                 return (EIO);
  553         dkrn = rid2rn(dr->dr_id);
  554         if (dkrn == 0) {
  555                 error = devfs_rule_autonumber(ds, &dkrn);
  556                 if (error != 0)
  557                         return (error);
  558         }
  559 
  560         dk = malloc(sizeof(*dk), M_DEVFS, M_WAITOK);
  561         dk->dk_ruleset = ds;
  562         if (dsi != NULL)
  563                 ++dsi->ds_refcount;
  564         /* XXX: Inspect dr? */
  565         memcpy(&dk->dk_rule, dr, sizeof(*dr));
  566         dk->dk_rule.dr_id = mkrid(rid2rsn(dk->dk_rule.dr_id), dkrn);
  567 
  568         k1 = SLIST_FIRST(&ds->ds_rules);
  569         if (k1 == NULL || rid2rn(k1->dk_rule.dr_id) > dkrn)
  570                 SLIST_INSERT_HEAD(&ds->ds_rules, dk, dk_list);
  571         else {
  572                 SLIST_FOREACH(k1, &ds->ds_rules, dk_list) {
  573                         k2 = SLIST_NEXT(k1, dk_list);
  574                         if (k2 == NULL || rid2rn(k2->dk_rule.dr_id) > dkrn) {
  575                                 SLIST_INSERT_AFTER(k1, dk, dk_list);
  576                                 break;
  577                         }
  578                 }
  579         }
  580 
  581         return (0);
  582 }
  583 
  584 /*
  585  * Determine whether dk matches de.  Returns 1 if dk should be run on
  586  * de; 0, otherwise.
  587  */
  588 static int
  589 devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de)
  590 {
  591         struct devfs_rule *dr = &dk->dk_rule;
  592         dev_t dev;
  593 
  594         dev = devfs_rule_getdev(de);
  595         /*
  596          * At this point, if dev is NULL, we should assume that any
  597          * criteria that depend on it don't match.  We should *not*
  598          * just ignore them (i.e., act like they weren't specified),
  599          * since that makes a rule that only has criteria dependent on
  600          * the dev_t match all symlinks and directories.
  601          *
  602          * Note also that the following tests are somewhat reversed:
  603          * They're actually testing to see whether the condition does
  604          * *not* match, since the default is to assume the rule should
  605          * be run (such as if there are no conditions).
  606          */
  607         if (dr->dr_icond & DRC_DSWFLAGS)
  608                 if (dev == NULL ||
  609                     (dev->si_devsw->d_flags & dr->dr_dswflags) == 0)
  610                         goto nomatch;
  611         if (dr->dr_icond & DRC_PATHPTRN)
  612                 if (!devfs_rule_matchpath(dk, de))
  613                         goto nomatch;
  614         if (dr->dr_icond & DRC_MAJOR)
  615                 if (dev == NULL || major(dev) != dr->dr_major)
  616                         goto nomatch;
  617 
  618         return (1);
  619 
  620 nomatch:
  621         return (0);
  622 }
  623 
  624 /*
  625  * Determine whether dk matches de on account of dr_pathptrn.
  626  */
  627 static int
  628 devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de)
  629 {
  630         struct devfs_rule *dr = &dk->dk_rule;
  631         char *pname;
  632         dev_t dev;
  633 
  634         dev = devfs_rule_getdev(de);
  635         if (dev != NULL)
  636                 pname = dev->si_name;
  637         /* XXX: Support symlinks (check d_type == DT_LNK here). */
  638         else
  639                 return (0);
  640         KASSERT(pname != NULL, ("devfs_rule_matchpath: NULL pname"));
  641 
  642         return (fnmatch(dr->dr_pathptrn, pname, 0) == 0);
  643 }
  644 
  645 /*
  646  * Run dk on de.
  647  */
  648 static void
  649 devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de)
  650 {
  651         struct devfs_rule *dr = &dk->dk_rule;
  652         struct devfs_ruleset *ds;
  653 
  654         if (dr->dr_iacts & DRA_BACTS) {
  655                 if (dr->dr_bacts & DRB_HIDE)
  656                         de->de_flags |= DE_WHITEOUT;
  657                 if (dr->dr_bacts & DRB_UNHIDE)
  658                         de->de_flags &= ~DE_WHITEOUT;
  659         }
  660         if (dr->dr_iacts & DRA_UID)
  661                 de->de_uid = dr->dr_uid;
  662         if (dr->dr_iacts & DRA_GID)
  663                 de->de_gid = dr->dr_gid;
  664         if (dr->dr_iacts & DRA_MODE)
  665                 de->de_mode = dr->dr_mode;
  666         if (dr->dr_iacts & DRA_INCSET) {
  667                 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  668                 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  669                 if (ds->ds_running)
  670                         printf("Warning: avoiding loop through ruleset %d\n",
  671                             ds->ds_number);
  672                 else
  673                         devfs_ruleset_applyde(ds, de);
  674         }
  675 }
  676 
  677 /*
  678  * Apply all the rules in ds to de.
  679  */
  680 static void
  681 devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de)
  682 {
  683         struct devfs_krule *dk;
  684 
  685         KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
  686         ds->ds_running = 1;
  687         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  688                 devfs_rule_applyde(dk, de);
  689         }
  690         ds->ds_running = 0;
  691 }
  692 
  693 /*
  694  * Apply all the rules in ds to all the entires in dm.
  695  */
  696 static void
  697 devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
  698 {
  699         struct devfs_krule *dk;
  700 
  701         KASSERT(!ds->ds_running,("ruleset %d already running", ds->ds_number));
  702         ds->ds_running = 1;
  703         /*
  704          * XXX: Does it matter whether we do
  705          *
  706          *      foreach(dk in ds)
  707          *              foreach(de in dm)
  708          *                      apply(dk to de)
  709          *
  710          * as opposed to
  711          *
  712          *      foreach(de in dm)
  713          *              foreach(dk in ds)
  714          *                      apply(dk to de)
  715          *
  716          * The end result is obviously the same, but does the order
  717          * matter?
  718          */
  719         SLIST_FOREACH(dk, &ds->ds_rules, dk_list) {
  720                 devfs_rule_applydm(dk, dm);
  721         }
  722         ds->ds_running = 0;
  723 }
  724 
  725 /*
  726  * Find a ruleset by number.
  727  */
  728 static struct devfs_ruleset *
  729 devfs_ruleset_bynum(devfs_rsnum rsnum)
  730 {
  731         struct devfs_ruleset *ds;
  732 
  733         SLIST_FOREACH(ds, &devfs_rulesets, ds_list) {
  734                 if (ds->ds_number == rsnum)
  735                         return (ds);
  736         }
  737         return (NULL);
  738 }
  739 
  740 /*
  741  * Create a new ruleset.
  742  */
  743 static struct devfs_ruleset *
  744 devfs_ruleset_create(devfs_rsnum rsnum)
  745 {
  746         struct devfs_ruleset *s1, *s2;
  747         struct devfs_ruleset *ds;
  748 
  749         KASSERT(devfs_ruleset_bynum(rsnum) == NULL,
  750             ("creating already existent ruleset %d", rsnum));
  751 
  752         ds = malloc(sizeof(*ds), M_DEVFS, M_WAITOK | M_ZERO);
  753         ds->ds_number = rsnum;
  754         ds->ds_refcount = ds->ds_flags = 0;
  755         SLIST_INIT(&ds->ds_rules);
  756 
  757         s1 = SLIST_FIRST(&devfs_rulesets);
  758         if (s1 == NULL || s1->ds_number > rsnum)
  759                 SLIST_INSERT_HEAD(&devfs_rulesets, ds, ds_list);
  760         else {
  761                 SLIST_FOREACH(s1, &devfs_rulesets, ds_list) {
  762                         s2 = SLIST_NEXT(s1, ds_list);
  763                         if (s2 == NULL || s2->ds_number > rsnum) {
  764                                 SLIST_INSERT_AFTER(s1, ds, ds_list);
  765                                 break;
  766                         }
  767                 }
  768         }
  769 
  770         return (ds);
  771 }
  772 
  773 /*
  774  * Remove a ruleset form the system.  The ruleset specified must be
  775  * empty and not in use.
  776  */
  777 static void
  778 devfs_ruleset_destroy(struct devfs_ruleset **dsp)
  779 {
  780         struct devfs_ruleset *ds = *dsp;
  781 
  782         KASSERT(SLIST_EMPTY(&ds->ds_rules), ("destroying non-empty ruleset"));
  783         KASSERT(ds->ds_refcount == 0, ("destroying busy ruleset"));
  784         KASSERT((ds->ds_flags & DS_IMMUTABLE) == 0,
  785             ("destroying immutable ruleset"));
  786 
  787         SLIST_REMOVE(&devfs_rulesets, ds, devfs_ruleset, ds_list);
  788         free(ds, M_DEVFS);
  789         *dsp = NULL;
  790 }
  791 
  792 /*
  793  * Remove a ruleset from the system if it's empty and not used
  794  * anywhere.  This should be called after every time a rule is deleted
  795  * from this ruleset or the reference count is decremented.
  796  */
  797 static void
  798 devfs_ruleset_reap(struct devfs_ruleset **dsp)
  799 {
  800         struct devfs_ruleset *ds = *dsp;
  801 
  802         if (SLIST_EMPTY(&ds->ds_rules) && ds->ds_refcount == 0) {
  803                 devfs_ruleset_destroy(&ds);
  804                 *dsp = ds;
  805         }
  806 }
  807 
  808 /*
  809  * Make rsnum the active ruleset for dm.
  810  */
  811 static int
  812 devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm)
  813 {
  814         struct devfs_ruleset *cds, *ds;
  815 
  816         ds = devfs_ruleset_bynum(rsnum);
  817         if (ds == NULL)
  818                 ds = devfs_ruleset_create(rsnum);
  819         cds = devfs_ruleset_bynum(dm->dm_ruleset);
  820         KASSERT(cds != NULL, ("mount-point has NULL ruleset"));
  821 
  822         /* These should probably be made atomic somehow. */
  823         --cds->ds_refcount;
  824         ++ds->ds_refcount;
  825         dm->dm_ruleset = rsnum;
  826 
  827         devfs_ruleset_reap(&cds);
  828         return (0);
  829 }
  830 
  831 #endif /* !NODEVFS */

Cache object: 2b318896c025f7c330873e67f6999efb


[ 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.