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/6.0/sys/fs/devfs/devfs_rule.c 150569 2005-09-26 14:36:54Z 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 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/conf.h>
   70 #include <sys/kernel.h>
   71 #include <sys/malloc.h>
   72 #include <sys/dirent.h>
   73 #include <sys/ioccom.h>
   74 #include <sys/lock.h>
   75 #include <sys/sx.h>
   76 
   77 #include <fs/devfs/devfs.h>
   78 #include <fs/devfs/devfs_int.h>
   79 
   80 /*
   81  * Kernel version of devfs_rule.
   82  */
   83 struct devfs_krule {
   84         TAILQ_ENTRY(devfs_krule)        dk_list;
   85         struct devfs_ruleset            *dk_ruleset;
   86         struct devfs_rule               dk_rule;
   87 };
   88 
   89 TAILQ_HEAD(rulehead, devfs_krule);
   90 static MALLOC_DEFINE(M_DEVFSRULE, "DEVFS_RULE", "DEVFS rule storage");
   91 
   92 /*
   93  * Structure to describe a ruleset.
   94  */
   95 struct devfs_ruleset {
   96         TAILQ_ENTRY(devfs_ruleset)      ds_list;
   97         struct rulehead                 ds_rules;
   98         devfs_rsnum                     ds_number;
   99         int                             ds_refcount;
  100 };
  101 
  102 static devfs_rid devfs_rid_input(devfs_rid rid, struct devfs_mount *dm);
  103 
  104 static void devfs_rule_applyde_recursive(struct devfs_krule *dk,
  105                 struct devfs_dirent *de);
  106 static void devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm);
  107 static int  devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnp);
  108 static struct devfs_krule *devfs_rule_byid(devfs_rid rid);
  109 static int  devfs_rule_delete(struct devfs_krule *dkp);
  110 static struct cdev *devfs_rule_getdev(struct devfs_dirent *de);
  111 static int  devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm);
  112 static int  devfs_rule_insert(struct devfs_rule *dr);
  113 static int  devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de);
  114 static int  devfs_rule_matchpath(struct devfs_krule *dk,
  115                 struct devfs_dirent *de);
  116 static void devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth);
  117 
  118 static void devfs_ruleset_applyde(struct devfs_ruleset *ds,
  119                 struct devfs_dirent *de, unsigned depth);
  120 static void devfs_ruleset_applydm(struct devfs_ruleset *ds,
  121                 struct devfs_mount *dm);
  122 static struct devfs_ruleset *devfs_ruleset_bynum(devfs_rsnum rsnum);
  123 static struct devfs_ruleset *devfs_ruleset_create(devfs_rsnum rsnum);
  124 static void devfs_ruleset_reap(struct devfs_ruleset *dsp);
  125 static int  devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm);
  126 
  127 static struct sx sx_rules;
  128 SX_SYSINIT(sx_rules, &sx_rules, "DEVFS ruleset lock");
  129 
  130 static TAILQ_HEAD(, devfs_ruleset) devfs_rulesets =
  131     TAILQ_HEAD_INITIALIZER(devfs_rulesets);
  132 
  133 /*
  134  * Called to apply the proper rules for 'de' before it can be
  135  * exposed to the userland.  This should be called with an exclusive
  136  * lock on dm in case we need to run anything.
  137  */
  138 void
  139 devfs_rules_apply(struct devfs_mount *dm, struct devfs_dirent *de)
  140 {
  141         struct devfs_ruleset *ds;
  142 
  143         if (dm->dm_ruleset == 0)
  144                 return;
  145         sx_slock(&sx_rules);
  146         ds = devfs_ruleset_bynum(dm->dm_ruleset);
  147         KASSERT(ds != NULL, ("mount-point has NULL ruleset"));
  148         devfs_ruleset_applyde(ds, de, devfs_rule_depth);
  149         sx_sunlock(&sx_rules);
  150 }
  151 
  152 /*
  153  * Rule subsystem ioctl hook.
  154  */
  155 int
  156 devfs_rules_ioctl(struct devfs_mount *dm, u_long cmd, caddr_t data, struct thread *td)
  157 {
  158         struct devfs_ruleset *ds;
  159         struct devfs_krule *dk;
  160         struct devfs_rule *dr;
  161         devfs_rsnum rsnum;
  162         devfs_rnum rnum;
  163         devfs_rid rid;
  164         int error;
  165 
  166         sx_assert(&dm->dm_lock, SX_XLOCKED);
  167 
  168         /*
  169          * XXX: This returns an error regardless of whether we
  170          * actually support the cmd or not.
  171          */
  172         error = suser(td);
  173         if (error != 0)
  174                 return (error);
  175 
  176         sx_xlock(&sx_rules);
  177 
  178         switch (cmd) {
  179         case DEVFSIO_RADD:
  180                 dr = (struct devfs_rule *)data;
  181                 error = devfs_rule_input(dr, dm);
  182                 if (error != 0)
  183                         break;
  184                 dk = devfs_rule_byid(dr->dr_id);
  185                 if (dk != NULL) {
  186                         error = EEXIST;
  187                         break;
  188                 }
  189                 if (rid2rsn(dr->dr_id) == 0)
  190                         return (EIO);
  191                 error = devfs_rule_insert(dr);
  192                 break;
  193         case DEVFSIO_RAPPLY:
  194                 dr = (struct devfs_rule *)data;
  195                 error = devfs_rule_input(dr, dm);
  196                 if (error != 0)
  197                         break;
  198 
  199                 /*
  200                  * This is one of many possible hackish
  201                  * implementations.  The primary contender is an
  202                  * implementation where the rule we read in is
  203                  * temporarily inserted into some ruleset, perhaps
  204                  * with a hypothetical DRO_NOAUTO flag so that it
  205                  * doesn't get used where it isn't intended, and
  206                  * applied in the normal way.  This can be done in the
  207                  * userland (DEVFSIO_ADD, DEVFSIO_APPLYID,
  208                  * DEVFSIO_DEL) or in the kernel; either way it breaks
  209                  * some corner case assumptions in other parts of the
  210                  * code (not that this implementation doesn't do
  211                  * that).
  212                  */
  213                 if (dr->dr_iacts & DRA_INCSET &&
  214                     devfs_ruleset_bynum(dr->dr_incset) == NULL) {
  215                         error = ESRCH;
  216                         break;
  217                 }
  218                 dk = malloc(sizeof(*dk), M_TEMP, M_WAITOK | M_ZERO);
  219                 memcpy(&dk->dk_rule, dr, sizeof(*dr));
  220                 devfs_rule_applydm(dk, dm);
  221                 free(dk, M_TEMP);
  222                 break;
  223         case DEVFSIO_RAPPLYID:
  224                 rid = *(devfs_rid *)data;
  225                 rid = devfs_rid_input(rid, dm);
  226                 dk = devfs_rule_byid(rid);
  227                 if (dk == NULL) {
  228                         error = ENOENT;
  229                         break;
  230                 }
  231                 devfs_rule_applydm(dk, dm);
  232                 break;
  233         case DEVFSIO_RDEL:
  234                 rid = *(devfs_rid *)data;
  235                 rid = devfs_rid_input(rid, dm);
  236                 dk = devfs_rule_byid(rid);
  237                 if (dk == NULL) {
  238                         error = ENOENT;
  239                         break;
  240                 }
  241                 ds = dk->dk_ruleset;
  242                 error = devfs_rule_delete(dk);
  243                 break;
  244         case DEVFSIO_RGETNEXT:
  245                 dr = (struct devfs_rule *)data;
  246                 error = devfs_rule_input(dr, dm);
  247                 if (error != 0)
  248                         break;
  249                 /*
  250                  * We can't use devfs_rule_byid() here since that
  251                  * requires the rule specified to exist, but we want
  252                  * getnext(N) to work whether there is a rule N or not
  253                  * (specifically, getnext(0) must work, but we should
  254                  * never have a rule 0 since the add command
  255                  * interprets 0 to mean "auto-number").
  256                  */
  257                 ds = devfs_ruleset_bynum(rid2rsn(dr->dr_id));
  258                 if (ds == NULL) {
  259                         error = ENOENT;
  260                         break;
  261                 }
  262                 rnum = rid2rn(dr->dr_id);
  263                 TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) {
  264                         if (rid2rn(dk->dk_rule.dr_id) > rnum)
  265                                 break;
  266                 }
  267                 if (dk == NULL) {
  268                         error = ENOENT;
  269                         break;
  270                 }
  271                 memcpy(dr, &dk->dk_rule, sizeof(*dr));
  272                 break;
  273         case DEVFSIO_SUSE:
  274                 rsnum = *(devfs_rsnum *)data;
  275                 error = devfs_ruleset_use(rsnum, dm);
  276                 break;
  277         case DEVFSIO_SAPPLY:
  278                 rsnum = *(devfs_rsnum *)data;
  279                 rsnum = rid2rsn(devfs_rid_input(mkrid(rsnum, 0), dm));
  280                 ds = devfs_ruleset_bynum(rsnum);
  281                 if (ds == NULL) {
  282                         error = ESRCH;
  283                         break;
  284                 }
  285                 devfs_ruleset_applydm(ds, dm);
  286                 break;
  287         case DEVFSIO_SGETNEXT:
  288                 rsnum = *(devfs_rsnum *)data;
  289                 TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) {
  290                         if (ds->ds_number > rsnum)
  291                                 break;
  292                 }
  293                 if (ds == NULL) {
  294                         error = ENOENT;
  295                         break;
  296                 }
  297                 *(devfs_rsnum *)data = ds->ds_number;
  298                 break;
  299         default:
  300                 error = ENOIOCTL;
  301                 break;
  302         }
  303 
  304         sx_xunlock(&sx_rules);
  305         return (error);
  306 }
  307 
  308 /*
  309  * Adjust the rule identifier to use the ruleset of dm if one isn't
  310  * explicitly specified.
  311  *
  312  * Note that after this operation, rid2rsn(rid) might still be 0, and
  313  * that's okay; ruleset 0 is a valid ruleset, but when it's read in
  314  * from the userland, it means "current ruleset for this mount-point".
  315  */
  316 static devfs_rid
  317 devfs_rid_input(devfs_rid rid, struct devfs_mount *dm)
  318 {
  319 
  320         if (rid2rsn(rid) == 0)
  321                 return (mkrid(dm->dm_ruleset, rid2rn(rid)));
  322         else
  323                 return (rid);
  324 }
  325 
  326 /*
  327  * Apply dk to de and everything under de.
  328  *
  329  * XXX: This method needs a function call for every nested
  330  * subdirectory in a devfs mount.  If we plan to have many of these,
  331  * we might eventually run out of kernel stack space.
  332  * XXX: a linear search could be done through the cdev list instead.
  333  */
  334 static void
  335 devfs_rule_applyde_recursive(struct devfs_krule *dk, struct devfs_dirent *de)
  336 {
  337         struct devfs_dirent *de2;
  338 
  339         TAILQ_FOREACH(de2, &de->de_dlist, de_list)
  340                 devfs_rule_applyde_recursive(dk, de2);
  341         devfs_rule_run(dk, de, devfs_rule_depth);
  342 }
  343 
  344 /*
  345  * Apply dk to all entires in dm.
  346  */
  347 static void
  348 devfs_rule_applydm(struct devfs_krule *dk, struct devfs_mount *dm)
  349 {
  350 
  351         devfs_rule_applyde_recursive(dk, dm->dm_rootdir);
  352 }
  353 
  354 /*
  355  * Automatically select a number for a new rule in ds, and write the
  356  * result into rnump.
  357  */
  358 static int
  359 devfs_rule_autonumber(struct devfs_ruleset *ds, devfs_rnum *rnump)
  360 {
  361         struct devfs_krule *dk;
  362 
  363         /* Find the last rule. */
  364         dk = TAILQ_LAST(&ds->ds_rules, rulehead);
  365         if (dk == NULL)
  366                 *rnump = 100;
  367         else {
  368                 *rnump = rid2rn(dk->dk_rule.dr_id) + 100;
  369                 /* Detect overflow. */
  370                 if (*rnump < rid2rn(dk->dk_rule.dr_id))
  371                         return (ERANGE);
  372         }
  373         KASSERT(devfs_rule_byid(mkrid(ds->ds_number, *rnump)) == NULL,
  374             ("autonumbering resulted in an already existing rule"));
  375         return (0);
  376 }
  377 
  378 /*
  379  * Find a krule by id.
  380  */
  381 static struct devfs_krule *
  382 devfs_rule_byid(devfs_rid rid)
  383 {
  384         struct devfs_ruleset *ds;
  385         struct devfs_krule *dk;
  386         devfs_rnum rn;
  387 
  388         rn = rid2rn(rid);
  389         ds = devfs_ruleset_bynum(rid2rsn(rid));
  390         if (ds == NULL)
  391                 return (NULL);
  392         TAILQ_FOREACH(dk, &ds->ds_rules, dk_list) {
  393                 if (rid2rn(dk->dk_rule.dr_id) == rn)
  394                         return (dk);
  395                 else if (rid2rn(dk->dk_rule.dr_id) > rn)
  396                         break;
  397         }
  398         return (NULL);
  399 }
  400 
  401 /*
  402  * Remove dkp from any lists it may be on and remove memory associated
  403  * with it.
  404  */
  405 static int
  406 devfs_rule_delete(struct devfs_krule *dk)
  407 {
  408         struct devfs_ruleset *ds;
  409 
  410         if (dk->dk_rule.dr_iacts & DRA_INCSET) {
  411                 ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  412                 KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  413                 --ds->ds_refcount;
  414                 devfs_ruleset_reap(ds);
  415         }
  416         ds = dk->dk_ruleset;
  417         TAILQ_REMOVE(&ds->ds_rules, dk, dk_list);
  418         devfs_ruleset_reap(ds);
  419         free(dk, M_DEVFSRULE);
  420         return (0);
  421 }
  422 
  423 /*
  424  * Get a struct cdev *corresponding to de so we can try to match rules based
  425  * on it.  If this routine returns NULL, there is no struct cdev *associated
  426  * with the dirent (symlinks and directories don't have dev_ts), and
  427  * the caller should assume that any critera dependent on a dev_t
  428  * don't match.
  429  */
  430 static struct cdev *
  431 devfs_rule_getdev(struct devfs_dirent *de)
  432 {
  433 
  434         if (de->de_cdp == NULL)
  435                 return (NULL);
  436         if (de->de_cdp->cdp_flags & CDP_ACTIVE)
  437                 return (&de->de_cdp->cdp_c);
  438         else
  439                 return (NULL);
  440 }
  441 
  442 /*
  443  * Do what we need to do to a rule that we just loaded from the
  444  * userland.  In particular, we need to check the magic, and adjust
  445  * the ruleset appropriate if desired.
  446  */
  447 static int
  448 devfs_rule_input(struct devfs_rule *dr, struct devfs_mount *dm)
  449 {
  450 
  451         if (dr->dr_magic != DEVFS_MAGIC)
  452                 return (ERPCMISMATCH);
  453         dr->dr_id = devfs_rid_input(dr->dr_id, dm);
  454         return (0);
  455 }
  456 
  457 /*
  458  * Import dr into the appropriate place in the kernel (i.e., make a
  459  * krule).  The value of dr is copied, so the pointer may be destroyed
  460  * after this call completes.
  461  */
  462 static int
  463 devfs_rule_insert(struct devfs_rule *dr)
  464 {
  465         struct devfs_ruleset *ds, *dsi;
  466         struct devfs_krule *k1;
  467         struct devfs_krule *dk;
  468         devfs_rsnum rsnum;
  469         devfs_rnum dkrn;
  470         int error;
  471 
  472         /*
  473          * This stuff seems out of place here, but we want to do it as
  474          * soon as possible so that if it fails, we don't have to roll
  475          * back any changes we already made (e.g., ruleset creation).
  476          */
  477         if (dr->dr_iacts & DRA_INCSET) {
  478                 dsi = devfs_ruleset_bynum(dr->dr_incset);
  479                 if (dsi == NULL)
  480                         return (ESRCH);
  481         } else
  482                 dsi = NULL;
  483 
  484         rsnum = rid2rsn(dr->dr_id);
  485         KASSERT(rsnum != 0, ("Inserting into ruleset zero"));
  486 
  487         ds = devfs_ruleset_bynum(rsnum);
  488         if (ds == NULL)
  489                 ds = devfs_ruleset_create(rsnum);
  490         dkrn = rid2rn(dr->dr_id);
  491         if (dkrn == 0) {
  492                 error = devfs_rule_autonumber(ds, &dkrn);
  493                 if (error != 0) {
  494                         devfs_ruleset_reap(ds);
  495                         return (error);
  496                 }
  497         }
  498 
  499         dk = malloc(sizeof(*dk), M_DEVFSRULE, M_WAITOK | M_ZERO);
  500         dk->dk_ruleset = ds;
  501         if (dsi != NULL)
  502                 ++dsi->ds_refcount;
  503         /* XXX: Inspect dr? */
  504         memcpy(&dk->dk_rule, dr, sizeof(*dr));
  505         dk->dk_rule.dr_id = mkrid(rid2rsn(dk->dk_rule.dr_id), dkrn);
  506 
  507         TAILQ_FOREACH(k1, &ds->ds_rules, dk_list) {
  508                 if (rid2rn(k1->dk_rule.dr_id) > dkrn) {
  509                         TAILQ_INSERT_BEFORE(k1, dk, dk_list);
  510                         break;
  511                 }
  512         }
  513         if (k1 == NULL)
  514                 TAILQ_INSERT_TAIL(&ds->ds_rules, dk, dk_list);
  515         return (0);
  516 }
  517 
  518 /*
  519  * Determine whether dk matches de.  Returns 1 if dk should be run on
  520  * de; 0, otherwise.
  521  */
  522 static int
  523 devfs_rule_match(struct devfs_krule *dk, struct devfs_dirent *de)
  524 {
  525         struct devfs_rule *dr = &dk->dk_rule;
  526         struct cdev *dev;
  527 
  528         dev = devfs_rule_getdev(de);
  529         /*
  530          * At this point, if dev is NULL, we should assume that any
  531          * criteria that depend on it don't match.  We should *not*
  532          * just ignore them (i.e., act like they weren't specified),
  533          * since that makes a rule that only has criteria dependent on
  534          * the struct cdev *match all symlinks and directories.
  535          *
  536          * Note also that the following tests are somewhat reversed:
  537          * They're actually testing to see whether the condition does
  538          * *not* match, since the default is to assume the rule should
  539          * be run (such as if there are no conditions).
  540          *
  541          * XXX: lacks threadref on dev
  542          */
  543         if (dr->dr_icond & DRC_DSWFLAGS)
  544                 if (dev == NULL ||
  545                     (dev->si_devsw->d_flags & dr->dr_dswflags) == 0)
  546                         return (0);
  547         if (dr->dr_icond & DRC_PATHPTRN)
  548                 if (!devfs_rule_matchpath(dk, de))
  549                         return (0);
  550 
  551         return (1);
  552 }
  553 
  554 /*
  555  * Determine whether dk matches de on account of dr_pathptrn.
  556  */
  557 static int
  558 devfs_rule_matchpath(struct devfs_krule *dk, struct devfs_dirent *de)
  559 {
  560         struct devfs_rule *dr = &dk->dk_rule;
  561         char *pname;
  562         struct cdev *dev;
  563 
  564         dev = devfs_rule_getdev(de);
  565         if (dev != NULL)
  566                 pname = dev->si_name;
  567         else if (de->de_dirent->d_type == DT_LNK ||
  568             de->de_dirent->d_type == DT_DIR)
  569                 pname = de->de_dirent->d_name;
  570         else
  571                 return (0);
  572         KASSERT(pname != NULL, ("devfs_rule_matchpath: NULL pname"));
  573 
  574         return (fnmatch(dr->dr_pathptrn, pname, 0) == 0);
  575 }
  576 
  577 /*
  578  * Run dk on de.
  579  */
  580 static void
  581 devfs_rule_run(struct devfs_krule *dk, struct devfs_dirent *de, unsigned depth)
  582 {
  583         struct devfs_rule *dr = &dk->dk_rule;
  584         struct devfs_ruleset *ds;
  585 
  586         if (!devfs_rule_match(dk, de))
  587                 return;
  588         if (dr->dr_iacts & DRA_BACTS) {
  589                 if (dr->dr_bacts & DRB_HIDE)
  590                         de->de_flags |= DE_WHITEOUT;
  591                 if (dr->dr_bacts & DRB_UNHIDE)
  592                         de->de_flags &= ~DE_WHITEOUT;
  593         }
  594         if (dr->dr_iacts & DRA_UID)
  595                 de->de_uid = dr->dr_uid;
  596         if (dr->dr_iacts & DRA_GID)
  597                 de->de_gid = dr->dr_gid;
  598         if (dr->dr_iacts & DRA_MODE)
  599                 de->de_mode = dr->dr_mode;
  600         if (dr->dr_iacts & DRA_INCSET) {
  601                 /*
  602                  * XXX: we should tell the user if the depth is exceeded here
  603                  * XXX: but it is not obvious how to.  A return value will
  604                  * XXX: not work as this is called when devices are created
  605                  * XXX: long time after the rules were instantiated.
  606                  * XXX: a printf() would probably give too much noise, or
  607                  * XXX: DoS the machine.  I guess a a rate-limited message
  608                  * XXX: might work.
  609                  */
  610                 if (depth > 0) {
  611                         ds = devfs_ruleset_bynum(dk->dk_rule.dr_incset);
  612                         KASSERT(ds != NULL, ("DRA_INCSET but bad dr_incset"));
  613                         devfs_ruleset_applyde(ds, de, depth - 1);
  614                 }
  615         }
  616 }
  617 
  618 /*
  619  * Apply all the rules in ds to de.
  620  */
  621 static void
  622 devfs_ruleset_applyde(struct devfs_ruleset *ds, struct devfs_dirent *de, unsigned depth)
  623 {
  624         struct devfs_krule *dk;
  625 
  626         TAILQ_FOREACH(dk, &ds->ds_rules, dk_list)
  627                 devfs_rule_run(dk, de, depth);
  628 }
  629 
  630 /*
  631  * Apply all the rules in ds to all the entires in dm.
  632  */
  633 static void
  634 devfs_ruleset_applydm(struct devfs_ruleset *ds, struct devfs_mount *dm)
  635 {
  636         struct devfs_krule *dk;
  637 
  638         /*
  639          * XXX: Does it matter whether we do
  640          *
  641          *      foreach(dk in ds)
  642          *              foreach(de in dm)
  643          *                      apply(dk to de)
  644          *
  645          * as opposed to
  646          *
  647          *      foreach(de in dm)
  648          *              foreach(dk in ds)
  649          *                      apply(dk to de)
  650          *
  651          * The end result is obviously the same, but does the order
  652          * matter?
  653          */
  654         TAILQ_FOREACH(dk, &ds->ds_rules, dk_list)
  655                 devfs_rule_applydm(dk, dm);
  656 }
  657 
  658 /*
  659  * Find a ruleset by number.
  660  */
  661 static struct devfs_ruleset *
  662 devfs_ruleset_bynum(devfs_rsnum rsnum)
  663 {
  664         struct devfs_ruleset *ds;
  665 
  666         TAILQ_FOREACH(ds, &devfs_rulesets, ds_list) {
  667                 if (ds->ds_number == rsnum)
  668                         return (ds);
  669         }
  670         return (NULL);
  671 }
  672 
  673 /*
  674  * Create a new ruleset.
  675  */
  676 static struct devfs_ruleset *
  677 devfs_ruleset_create(devfs_rsnum rsnum)
  678 {
  679         struct devfs_ruleset *s1;
  680         struct devfs_ruleset *ds;
  681 
  682         KASSERT(rsnum != 0, ("creating ruleset zero"));
  683 
  684         KASSERT(devfs_ruleset_bynum(rsnum) == NULL,
  685             ("creating already existent ruleset %d", rsnum));
  686 
  687         ds = malloc(sizeof(*ds), M_DEVFSRULE, M_WAITOK | M_ZERO);
  688         ds->ds_number = rsnum;
  689         TAILQ_INIT(&ds->ds_rules);
  690 
  691         TAILQ_FOREACH(s1, &devfs_rulesets, ds_list) {
  692                 if (s1->ds_number > rsnum) {
  693                         TAILQ_INSERT_BEFORE(s1, ds, ds_list);
  694                         break;
  695                 }
  696         }
  697         if (s1 == NULL)
  698                 TAILQ_INSERT_TAIL(&devfs_rulesets, ds, ds_list);
  699         return (ds);
  700 }
  701 
  702 /*
  703  * Remove a ruleset from the system if it's empty and not used
  704  * anywhere.  This should be called after every time a rule is deleted
  705  * from this ruleset or the reference count is decremented.
  706  */
  707 static void
  708 devfs_ruleset_reap(struct devfs_ruleset *ds)
  709 {
  710 
  711         KASSERT(ds->ds_number != 0, ("reaping ruleset zero "));
  712 
  713         if (!TAILQ_EMPTY(&ds->ds_rules) || ds->ds_refcount != 0) 
  714                 return;
  715 
  716         TAILQ_REMOVE(&devfs_rulesets, ds, ds_list);
  717         free(ds, M_DEVFSRULE);
  718 }
  719 
  720 /*
  721  * Make rsnum the active ruleset for dm.
  722  */
  723 static int
  724 devfs_ruleset_use(devfs_rsnum rsnum, struct devfs_mount *dm)
  725 {
  726         struct devfs_ruleset *cds, *ds;
  727 
  728         ds = devfs_ruleset_bynum(rsnum);
  729         if (ds == NULL)
  730                 ds = devfs_ruleset_create(rsnum);
  731         if (dm->dm_ruleset != 0) {
  732                 cds = devfs_ruleset_bynum(dm->dm_ruleset);
  733                 --cds->ds_refcount;
  734                 devfs_ruleset_reap(cds);
  735         }
  736 
  737         /* These should probably be made atomic somehow. */
  738         ++ds->ds_refcount;
  739         dm->dm_ruleset = rsnum;
  740 
  741         return (0);
  742 }
  743 
  744 void
  745 devfs_rules_cleanup(struct devfs_mount *dm)
  746 {
  747         struct devfs_ruleset *ds;
  748 
  749         sx_assert(&dm->dm_lock, SX_XLOCKED);
  750         if (dm->dm_ruleset != 0) {
  751                 ds = devfs_ruleset_bynum(dm->dm_ruleset);
  752                 --ds->ds_refcount;
  753                 devfs_ruleset_reap(ds);
  754         }
  755 }

Cache object: 1c0e8a7647fa54f504fe534407e55401


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