xref: /dflybsd-src/sys/vfs/devfs/devfs_rules.c (revision dae650601b7a1502cc3804a70c39222b46186f48)
121864bc5SMatthew Dillon /*
221864bc5SMatthew Dillon  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
321864bc5SMatthew Dillon  *
421864bc5SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
521864bc5SMatthew Dillon  * by Alex Hornung <ahornung@gmail.com>
621864bc5SMatthew Dillon  *
721864bc5SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
821864bc5SMatthew Dillon  * modification, are permitted provided that the following conditions
921864bc5SMatthew Dillon  * are met:
1021864bc5SMatthew Dillon  *
1121864bc5SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
1221864bc5SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
1321864bc5SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
1421864bc5SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
1521864bc5SMatthew Dillon  *    the documentation and/or other materials provided with the
1621864bc5SMatthew Dillon  *    distribution.
1721864bc5SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
1821864bc5SMatthew Dillon  *    contributors may be used to endorse or promote products derived
1921864bc5SMatthew Dillon  *    from this software without specific, prior written permission.
2021864bc5SMatthew Dillon  *
2121864bc5SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2221864bc5SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2321864bc5SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2421864bc5SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
2521864bc5SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2621864bc5SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2721864bc5SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2821864bc5SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2921864bc5SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3021864bc5SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3121864bc5SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3221864bc5SMatthew Dillon  * SUCH DAMAGE.
3321864bc5SMatthew Dillon  */
3421864bc5SMatthew Dillon #include <sys/param.h>
3521864bc5SMatthew Dillon #include <sys/systm.h>
3621864bc5SMatthew Dillon #include <sys/kernel.h>
37*dae65060Szrj #include <sys/malloc.h>
384464e289SAlex Hornung #include <sys/lock.h>
394464e289SAlex Hornung #include <sys/spinlock2.h>
4021864bc5SMatthew Dillon #include <sys/fcntl.h>
4121864bc5SMatthew Dillon #include <sys/device.h>
4221864bc5SMatthew Dillon #include <sys/mount.h>
432c1e28ddSAlex Hornung #include <sys/devfs.h>
442c1e28ddSAlex Hornung #include <sys/devfs_rules.h>
4521864bc5SMatthew Dillon 
4621864bc5SMatthew Dillon MALLOC_DECLARE(M_DEVFS);
4721864bc5SMatthew Dillon 
4821864bc5SMatthew Dillon static d_open_t      devfs_dev_open;
4921864bc5SMatthew Dillon static d_close_t     devfs_dev_close;
5021864bc5SMatthew Dillon static d_ioctl_t     devfs_dev_ioctl;
5121864bc5SMatthew Dillon 
525704df1dSAlex Hornung static struct devfs_rule *devfs_rule_alloc(struct devfs_rule_ioctl *);
5321864bc5SMatthew Dillon static void devfs_rule_free(struct devfs_rule *);
54dd8bea0aSAlex Hornung static int devfs_rule_insert(struct devfs_rule_ioctl *);
5521864bc5SMatthew Dillon static void devfs_rule_remove(struct devfs_rule *);
56dd8bea0aSAlex Hornung static int devfs_rule_clear(struct devfs_rule_ioctl *);
5784ba2ba8SAlex Hornung static void devfs_rule_create_link(struct devfs_node *, struct devfs_rule *);
5821864bc5SMatthew Dillon static int devfs_rule_checkname(struct devfs_rule *, struct devfs_node *);
5921864bc5SMatthew Dillon 
6021864bc5SMatthew Dillon static struct objcache	*devfs_rule_cache;
6121864bc5SMatthew Dillon static struct lock	devfs_rule_lock;
6221864bc5SMatthew Dillon 
6321864bc5SMatthew Dillon static struct objcache_malloc_args devfs_rule_malloc_args = {
6421864bc5SMatthew Dillon 	sizeof(struct devfs_rule), M_DEVFS };
6521864bc5SMatthew Dillon 
6621864bc5SMatthew Dillon static cdev_t devfs_dev;
67bc185c5aSAlex Hornung static struct devfs_rule_head devfs_rule_list =
68bc185c5aSAlex Hornung 		TAILQ_HEAD_INITIALIZER(devfs_rule_list);
6921864bc5SMatthew Dillon 
7021864bc5SMatthew Dillon static struct dev_ops devfs_dev_ops = {
71c0739b3cSMatthew Dillon 	{ "devfs", 0, D_MPSAFE },
7221864bc5SMatthew Dillon 	.d_open = devfs_dev_open,
7321864bc5SMatthew Dillon 	.d_close = devfs_dev_close,
7421864bc5SMatthew Dillon 	.d_ioctl = devfs_dev_ioctl
7521864bc5SMatthew Dillon };
7621864bc5SMatthew Dillon 
7721864bc5SMatthew Dillon 
7821864bc5SMatthew Dillon static struct devfs_rule *
devfs_rule_alloc(struct devfs_rule_ioctl * templ)795704df1dSAlex Hornung devfs_rule_alloc(struct devfs_rule_ioctl *templ)
8021864bc5SMatthew Dillon {
81894bbb25SAlex Hornung 	struct devfs_rule *rule;
825704df1dSAlex Hornung 	size_t len;
8321864bc5SMatthew Dillon 
84894bbb25SAlex Hornung 	rule = objcache_get(devfs_rule_cache, M_WAITOK);
85894bbb25SAlex Hornung 	memset(rule, 0, sizeof(struct devfs_rule));
86894bbb25SAlex Hornung 
87dd8bea0aSAlex Hornung 	if (templ->mntpoint == NULL)
88dd8bea0aSAlex Hornung 		goto error_out;
89dd8bea0aSAlex Hornung 		/* NOTREACHED */
90dd8bea0aSAlex Hornung 
915704df1dSAlex Hornung 	len = strlen(templ->mntpoint);
92dd8bea0aSAlex Hornung 	if (len == 0)
93dd8bea0aSAlex Hornung 		goto error_out;
94dd8bea0aSAlex Hornung 		/* NOTREACHED */
95dd8bea0aSAlex Hornung 
965704df1dSAlex Hornung 	rule->mntpoint = kstrdup(templ->mntpoint, M_DEVFS);
975704df1dSAlex Hornung 	rule->mntpointlen = len;
98894bbb25SAlex Hornung 
99dd8bea0aSAlex Hornung 	if (templ->rule_type & DEVFS_RULE_NAME) {
100dd8bea0aSAlex Hornung 		if (templ->name == NULL)
101dd8bea0aSAlex Hornung 			goto error_out;
102dd8bea0aSAlex Hornung 			/* NOTREACHED */
103dd8bea0aSAlex Hornung 
1045704df1dSAlex Hornung 		len = strlen(templ->name);
105dd8bea0aSAlex Hornung 		if (len == 0)
106dd8bea0aSAlex Hornung 			goto error_out;
107dd8bea0aSAlex Hornung 			/* NOTREACHED */
108dd8bea0aSAlex Hornung 
1095704df1dSAlex Hornung 		rule->name = kstrdup(templ->name, M_DEVFS);
1105704df1dSAlex Hornung 		rule->namlen = len;
1115704df1dSAlex Hornung 	}
112894bbb25SAlex Hornung 
113dd8bea0aSAlex Hornung 	if (templ->rule_cmd & DEVFS_RULE_LINK) {
114dd8bea0aSAlex Hornung 		if (templ->linkname == NULL)
115dd8bea0aSAlex Hornung 			goto error_out;
116dd8bea0aSAlex Hornung 			/* NOTREACHED */
117dd8bea0aSAlex Hornung 
1185704df1dSAlex Hornung 		len = strlen(templ->linkname);
119dd8bea0aSAlex Hornung 		if (len == 0)
120dd8bea0aSAlex Hornung 			goto error_out;
121dd8bea0aSAlex Hornung 			/* NOTREACHED */
122dd8bea0aSAlex Hornung 
1235704df1dSAlex Hornung 		rule->linkname = kstrdup(templ->linkname, M_DEVFS);
1245704df1dSAlex Hornung 		rule->linknamlen = len;
1255704df1dSAlex Hornung 	}
126894bbb25SAlex Hornung 
127894bbb25SAlex Hornung 	rule->rule_type = templ->rule_type;
1285704df1dSAlex Hornung 	rule->rule_cmd = templ->rule_cmd;
129894bbb25SAlex Hornung 	rule->dev_type = templ->dev_type;
130894bbb25SAlex Hornung 	rule->mode = templ->mode;
131894bbb25SAlex Hornung 	rule->uid = templ->uid;
132894bbb25SAlex Hornung 	rule->gid = templ->gid;
133894bbb25SAlex Hornung 
13421864bc5SMatthew Dillon 	return rule;
135dd8bea0aSAlex Hornung 
136dd8bea0aSAlex Hornung error_out:
137dd8bea0aSAlex Hornung 	devfs_rule_free(rule);
138dd8bea0aSAlex Hornung 	return NULL;
13921864bc5SMatthew Dillon }
14021864bc5SMatthew Dillon 
14121864bc5SMatthew Dillon 
14221864bc5SMatthew Dillon static void
devfs_rule_free(struct devfs_rule * rule)14321864bc5SMatthew Dillon devfs_rule_free(struct devfs_rule *rule)
14421864bc5SMatthew Dillon {
145894bbb25SAlex Hornung 	if (rule->mntpoint != NULL) {
146894bbb25SAlex Hornung 		kfree(rule->mntpoint, M_DEVFS);
147894bbb25SAlex Hornung 	}
148894bbb25SAlex Hornung 
149894bbb25SAlex Hornung 	if (rule->name != NULL) {
150894bbb25SAlex Hornung 		kfree(rule->name, M_DEVFS);
151894bbb25SAlex Hornung 	}
152894bbb25SAlex Hornung 
153894bbb25SAlex Hornung 	if (rule->linkname != NULL) {
154894bbb25SAlex Hornung 		kfree(rule->linkname, M_DEVFS);
155894bbb25SAlex Hornung 	}
15621864bc5SMatthew Dillon 	objcache_put(devfs_rule_cache, rule);
15721864bc5SMatthew Dillon }
15821864bc5SMatthew Dillon 
15921864bc5SMatthew Dillon 
160dd8bea0aSAlex Hornung static int
devfs_rule_insert(struct devfs_rule_ioctl * templ)1615704df1dSAlex Hornung devfs_rule_insert(struct devfs_rule_ioctl *templ)
16221864bc5SMatthew Dillon {
163894bbb25SAlex Hornung 	struct devfs_rule *rule;
164894bbb25SAlex Hornung 
165894bbb25SAlex Hornung 	rule = devfs_rule_alloc(templ);
166dd8bea0aSAlex Hornung 	if (rule == NULL)
167dd8bea0aSAlex Hornung 		return EINVAL;
168894bbb25SAlex Hornung 
16921864bc5SMatthew Dillon 	lockmgr(&devfs_rule_lock, LK_EXCLUSIVE);
17021864bc5SMatthew Dillon 	TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
17121864bc5SMatthew Dillon 	lockmgr(&devfs_rule_lock, LK_RELEASE);
172dd8bea0aSAlex Hornung 
173dd8bea0aSAlex Hornung 	return 0;
17421864bc5SMatthew Dillon }
17521864bc5SMatthew Dillon 
17621864bc5SMatthew Dillon 
17721864bc5SMatthew Dillon static void
devfs_rule_remove(struct devfs_rule * rule)17821864bc5SMatthew Dillon devfs_rule_remove(struct devfs_rule *rule)
17921864bc5SMatthew Dillon {
18021864bc5SMatthew Dillon 	TAILQ_REMOVE(&devfs_rule_list, rule, link);
18121864bc5SMatthew Dillon 	devfs_rule_free(rule);
18221864bc5SMatthew Dillon }
18321864bc5SMatthew Dillon 
18421864bc5SMatthew Dillon 
185dd8bea0aSAlex Hornung static int
devfs_rule_clear(struct devfs_rule_ioctl * templ)1865704df1dSAlex Hornung devfs_rule_clear(struct devfs_rule_ioctl *templ)
18721864bc5SMatthew Dillon {
1885704df1dSAlex Hornung 	struct devfs_rule *rule1, *rule2;
189dd8bea0aSAlex Hornung 	size_t mntpointlen;
190dd8bea0aSAlex Hornung 
191dd8bea0aSAlex Hornung 	if (templ->mntpoint == NULL)
192dd8bea0aSAlex Hornung 		return EINVAL;
193dd8bea0aSAlex Hornung 
194dd8bea0aSAlex Hornung 	mntpointlen = strlen(templ->mntpoint);
195dd8bea0aSAlex Hornung 	if (mntpointlen == 0)
196dd8bea0aSAlex Hornung 		return EINVAL;
19721864bc5SMatthew Dillon 
19821864bc5SMatthew Dillon 	lockmgr(&devfs_rule_lock, LK_EXCLUSIVE);
19921864bc5SMatthew Dillon 	TAILQ_FOREACH_MUTABLE(rule1, &devfs_rule_list, link, rule2) {
2005704df1dSAlex Hornung 		if ((templ->mntpoint[0] == '*') ||
2015704df1dSAlex Hornung 		    ((mntpointlen == rule1->mntpointlen) &&
2025704df1dSAlex Hornung 		     (!memcmp(templ->mntpoint, rule1->mntpoint, mntpointlen)))) {
20321864bc5SMatthew Dillon 			devfs_rule_remove(rule1);
20421864bc5SMatthew Dillon 		}
20521864bc5SMatthew Dillon 	}
20621864bc5SMatthew Dillon 	lockmgr(&devfs_rule_lock, LK_RELEASE);
207dd8bea0aSAlex Hornung 
208dd8bea0aSAlex Hornung 	return 0;
20921864bc5SMatthew Dillon }
21021864bc5SMatthew Dillon 
21121864bc5SMatthew Dillon 
21266abefa5SAlex Hornung void *
devfs_rule_reset_node(struct devfs_node * node,void * unused)21366abefa5SAlex Hornung devfs_rule_reset_node(struct devfs_node *node, void *unused)
21421864bc5SMatthew Dillon {
2151cb12919SAlex Hornung 	/*
2160182b316SAlex Hornung 	 * Don't blindly unhide all devices, some, like unix98 pty masters,
2171cb12919SAlex Hornung 	 * haven't been hidden by a rule.
2181cb12919SAlex Hornung 	 */
2190182b316SAlex Hornung 	if (node->flags & DEVFS_RULE_HIDDEN)
2200182b316SAlex Hornung 		node->flags &= ~(DEVFS_HIDDEN | DEVFS_RULE_HIDDEN);
22121864bc5SMatthew Dillon 
2228e78a293SSascha Wildner 	if ((node->node_type == Nlink) && (node->flags & DEVFS_RULE_CREATED)) {
2231cb12919SAlex Hornung 		KKASSERT(node->link_target);
2241cb12919SAlex Hornung 		node->flags &= ~DEVFS_RULE_CREATED;
2251cb12919SAlex Hornung 		--node->link_target->nlinks;
2261cb12919SAlex Hornung 		devfs_gc(node);
2278e78a293SSascha Wildner 	} else if ((node->node_type == Ndev) && (node->d_dev)) {
22821864bc5SMatthew Dillon 		node->uid = node->d_dev->si_uid;
22921864bc5SMatthew Dillon 		node->gid = node->d_dev->si_gid;
23021864bc5SMatthew Dillon 		node->mode = node->d_dev->si_perms;
23121864bc5SMatthew Dillon 	}
23221864bc5SMatthew Dillon 
23366abefa5SAlex Hornung 	return NULL;
23421864bc5SMatthew Dillon }
23521864bc5SMatthew Dillon 
23684ba2ba8SAlex Hornung static void
devfs_rule_create_link(struct devfs_node * node,struct devfs_rule * rule)23784ba2ba8SAlex Hornung devfs_rule_create_link(struct devfs_node *node, struct devfs_rule *rule)
23884ba2ba8SAlex Hornung {
23984ba2ba8SAlex Hornung 	size_t len = 0;
24084ba2ba8SAlex Hornung 	char *path = NULL;
24184ba2ba8SAlex Hornung 	char *name, name_buf[PATH_MAX], buf[PATH_MAX];
24284ba2ba8SAlex Hornung 
24384ba2ba8SAlex Hornung 	if (rule->name[rule->namlen-1] == '*') {
24484ba2ba8SAlex Hornung 		devfs_resolve_name_path(rule->name, name_buf, &path, &name);
24584ba2ba8SAlex Hornung 		len = strlen(name);
24684ba2ba8SAlex Hornung 		--len;
24784ba2ba8SAlex Hornung 		ksnprintf(buf, sizeof(buf), "%s%s",
24884ba2ba8SAlex Hornung 		    rule->linkname, node->d_dir.d_name+len);
24984ba2ba8SAlex Hornung 		devfs_alias_create(buf, node, 1);
25084ba2ba8SAlex Hornung 	} else {
25184ba2ba8SAlex Hornung 		devfs_alias_create(rule->linkname, node, 1);
25284ba2ba8SAlex Hornung 	}
25384ba2ba8SAlex Hornung }
25421864bc5SMatthew Dillon 
25566abefa5SAlex Hornung void *
devfs_rule_check_apply(struct devfs_node * node,void * unused)25666abefa5SAlex Hornung devfs_rule_check_apply(struct devfs_node *node, void *unused)
25721864bc5SMatthew Dillon {
25821864bc5SMatthew Dillon 	struct devfs_rule *rule;
25921864bc5SMatthew Dillon 	struct mount *mp = node->mp;
2604464e289SAlex Hornung 	int locked = 0;
26121864bc5SMatthew Dillon 
2624464e289SAlex Hornung 	/* Check if it is locked already. if not, we acquire the devfs lock */
263ab08ac79SSascha Wildner 	if ((lockstatus(&devfs_rule_lock, curthread)) != LK_EXCLUSIVE) {
26421864bc5SMatthew Dillon 		lockmgr(&devfs_rule_lock, LK_EXCLUSIVE);
2654464e289SAlex Hornung 		locked = 1;
2664464e289SAlex Hornung 	}
2674464e289SAlex Hornung 
26821864bc5SMatthew Dillon 	TAILQ_FOREACH(rule, &devfs_rule_list, link) {
26921864bc5SMatthew Dillon 		/*
27021864bc5SMatthew Dillon 		 * Skip this rule if it is only intended for jailed mount points
27121864bc5SMatthew Dillon 		 * and the current mount point isn't jailed
27221864bc5SMatthew Dillon 		 */
27321864bc5SMatthew Dillon 		if ((rule->rule_type & DEVFS_RULE_JAIL) &&
27421864bc5SMatthew Dillon 			(!(DEVFS_MNTDATA(mp)->jailed)) )
27521864bc5SMatthew Dillon 			continue;
27621864bc5SMatthew Dillon 
27721864bc5SMatthew Dillon 		/*
278a4aa064cSAlex Hornung 		 * Skip this rule if it is not intended for jailed mount points
279a4aa064cSAlex Hornung 		 * and the current mount point is jailed.
280a4aa064cSAlex Hornung 		 */
281a4aa064cSAlex Hornung 		if (!(rule->rule_type & DEVFS_RULE_JAIL) &&
282a4aa064cSAlex Hornung 			(DEVFS_MNTDATA(mp)->jailed))
283a4aa064cSAlex Hornung 		    continue;
284a4aa064cSAlex Hornung 
285a4aa064cSAlex Hornung 		/*
28621864bc5SMatthew Dillon 		 * Skip this rule if the mount point specified in the rule doesn't
28721864bc5SMatthew Dillon 		 * match the mount point of the node
28821864bc5SMatthew Dillon 		 */
28921864bc5SMatthew Dillon 		if ((rule->mntpoint[0] != '*') &&
2909cf39e57SAlex Hornung 			(strcmp(rule->mntpoint, mp->mnt_stat.f_mntonname)))
29121864bc5SMatthew Dillon 			continue;
29221864bc5SMatthew Dillon 
29321864bc5SMatthew Dillon 		/*
29421864bc5SMatthew Dillon 		 * Skip this rule if this is a by-type rule and the device flags
29521864bc5SMatthew Dillon 		 * don't match the specified device type in the rule
29621864bc5SMatthew Dillon 		 */
29721864bc5SMatthew Dillon 		if ((rule->rule_type & DEVFS_RULE_TYPE) &&
29821864bc5SMatthew Dillon 			( (rule->dev_type == 0) || (!dev_is_good(node->d_dev)) ||
2994464e289SAlex Hornung 			  (!(dev_dflags(node->d_dev) & rule->dev_type))) )
30021864bc5SMatthew Dillon 			continue;
30121864bc5SMatthew Dillon 
30221864bc5SMatthew Dillon 		/*
30321864bc5SMatthew Dillon 		 * Skip this rule if this is a by-name rule and the node name
30421864bc5SMatthew Dillon 		 * doesn't match the wildcard string in the rule
30521864bc5SMatthew Dillon 		 */
30621864bc5SMatthew Dillon 		if ((rule->rule_type & DEVFS_RULE_NAME) &&
30721864bc5SMatthew Dillon 			(!devfs_rule_checkname(rule, node)) )
30821864bc5SMatthew Dillon 			continue;
30921864bc5SMatthew Dillon 
3105704df1dSAlex Hornung 		if (rule->rule_cmd & DEVFS_RULE_HIDE) {
31121864bc5SMatthew Dillon 			/*
31221864bc5SMatthew Dillon 			 * If we should hide the device, we just apply the relevant
31321864bc5SMatthew Dillon 			 * hide flag to the node and let devfs do the rest in the
31421864bc5SMatthew Dillon 			 * vnops
31521864bc5SMatthew Dillon 			 */
316801ada31SAlex Hornung 			if ((node->d_dir.d_namlen == 5) &&
317801ada31SAlex Hornung 				(!memcmp(node->d_dir.d_name, "devfs", 5))) {
318801ada31SAlex Hornung 				/*
319801ada31SAlex Hornung 				 * Magically avoid /dev/devfs from being hidden, so that one
320801ada31SAlex Hornung 				 * can still use the rule system even after a "* hide".
321801ada31SAlex Hornung 				 */
322801ada31SAlex Hornung 				 continue;
323801ada31SAlex Hornung 			}
3240182b316SAlex Hornung 			node->flags |= (DEVFS_HIDDEN | DEVFS_RULE_HIDDEN);
3255704df1dSAlex Hornung 		} else if (rule->rule_cmd & DEVFS_RULE_SHOW) {
32621864bc5SMatthew Dillon 			/*
32721864bc5SMatthew Dillon 			 * Show rule just means that the node should not be hidden, so
32821864bc5SMatthew Dillon 			 * what we do is clear the hide flag from the node.
32921864bc5SMatthew Dillon 			 */
33021864bc5SMatthew Dillon 			node->flags &= ~DEVFS_HIDDEN;
3319cf39e57SAlex Hornung 		} else if (rule->rule_cmd & DEVFS_RULE_LINK) {
33221864bc5SMatthew Dillon 			/*
33321864bc5SMatthew Dillon 			 * This is a LINK rule, so we tell devfs to create
33421864bc5SMatthew Dillon 			 * a link with the correct name to this node.
33521864bc5SMatthew Dillon 			 */
33684ba2ba8SAlex Hornung 			devfs_rule_create_link(node, rule);
33784ba2ba8SAlex Hornung #if 0
3381cb12919SAlex Hornung 			devfs_alias_create(rule->linkname, node, 1);
33984ba2ba8SAlex Hornung #endif
3405704df1dSAlex Hornung 		} else if (rule->rule_cmd & DEVFS_RULE_PERM) {
34121864bc5SMatthew Dillon 			/*
34221864bc5SMatthew Dillon 			 * This is a normal ownership/permission rule. We
34321864bc5SMatthew Dillon 			 * just apply the permissions and ownership and
34421864bc5SMatthew Dillon 			 * we are done.
34521864bc5SMatthew Dillon 			 */
34621864bc5SMatthew Dillon 			node->mode = rule->mode;
34721864bc5SMatthew Dillon 			node->uid = rule->uid;
34821864bc5SMatthew Dillon 			node->gid = rule->gid;
34921864bc5SMatthew Dillon 		}
35021864bc5SMatthew Dillon 	}
3514464e289SAlex Hornung 
3524464e289SAlex Hornung 	/* If we acquired the lock, we also get rid of it */
3534464e289SAlex Hornung 	if (locked)
35421864bc5SMatthew Dillon 		lockmgr(&devfs_rule_lock, LK_RELEASE);
3554464e289SAlex Hornung 
35666abefa5SAlex Hornung 	return NULL;
35721864bc5SMatthew Dillon }
35821864bc5SMatthew Dillon 
35921864bc5SMatthew Dillon 
36021864bc5SMatthew Dillon static int
devfs_rule_checkname(struct devfs_rule * rule,struct devfs_node * node)36121864bc5SMatthew Dillon devfs_rule_checkname(struct devfs_rule *rule, struct devfs_node *node)
36221864bc5SMatthew Dillon {
36321864bc5SMatthew Dillon 	struct devfs_node *parent = DEVFS_MNTDATA(node->mp)->root_node;
36421864bc5SMatthew Dillon 	char *path = NULL;
36521864bc5SMatthew Dillon 	char *name, name_buf[PATH_MAX];
36621864bc5SMatthew Dillon 	int no_match = 0;
36721864bc5SMatthew Dillon 
36821864bc5SMatthew Dillon 	devfs_resolve_name_path(rule->name, name_buf, &path, &name);
36921864bc5SMatthew Dillon 	parent = devfs_resolve_or_create_path(parent, path, 0);
37021864bc5SMatthew Dillon 
37121864bc5SMatthew Dillon 	if (parent == NULL)
37221864bc5SMatthew Dillon 		return 0; /* no match */
37321864bc5SMatthew Dillon 
37421864bc5SMatthew Dillon 	/* Check if node is a child of the parent we found */
37521864bc5SMatthew Dillon 	if (node->parent != parent)
37621864bc5SMatthew Dillon 		return 0; /* no match */
37721864bc5SMatthew Dillon 
37884ba2ba8SAlex Hornung #if 0
37921864bc5SMatthew Dillon 	if (rule->rule_type & DEVFS_RULE_LINK)
38021864bc5SMatthew Dillon 		no_match = memcmp(name, node->d_dir.d_name, strlen(name));
38121864bc5SMatthew Dillon 	else
38284ba2ba8SAlex Hornung #endif
3838312ca30SAlex Hornung 	no_match = devfs_WildCaseCmp(name, node->d_dir.d_name);
38421864bc5SMatthew Dillon 
38521864bc5SMatthew Dillon 	return !no_match;
38621864bc5SMatthew Dillon }
38721864bc5SMatthew Dillon 
38821864bc5SMatthew Dillon 
38921864bc5SMatthew Dillon static int
devfs_dev_open(struct dev_open_args * ap)39021864bc5SMatthew Dillon devfs_dev_open(struct dev_open_args *ap)
39121864bc5SMatthew Dillon {
39221864bc5SMatthew Dillon 	/*
39321864bc5SMatthew Dillon 	 * Only allow read-write access.
39421864bc5SMatthew Dillon 	 */
39521864bc5SMatthew Dillon 	if (((ap->a_oflags & FWRITE) == 0) || ((ap->a_oflags & FREAD) == 0))
39621864bc5SMatthew Dillon 		return(EPERM);
39721864bc5SMatthew Dillon 
39821864bc5SMatthew Dillon 	/*
39921864bc5SMatthew Dillon 	 * We don't allow nonblocking access.
40021864bc5SMatthew Dillon 	 */
40121864bc5SMatthew Dillon 	if ((ap->a_oflags & O_NONBLOCK) != 0) {
402c0739b3cSMatthew Dillon 		devfs_debug(DEVFS_DEBUG_SHOW,
403c0739b3cSMatthew Dillon 			    "devfs_dev: can't do nonblocking access\n");
40421864bc5SMatthew Dillon 		return(ENODEV);
40521864bc5SMatthew Dillon 	}
40621864bc5SMatthew Dillon 
40721864bc5SMatthew Dillon 	return 0;
40821864bc5SMatthew Dillon }
40921864bc5SMatthew Dillon 
41021864bc5SMatthew Dillon 
41121864bc5SMatthew Dillon static int
devfs_dev_close(struct dev_close_args * ap)41221864bc5SMatthew Dillon devfs_dev_close(struct dev_close_args *ap)
41321864bc5SMatthew Dillon {
41421864bc5SMatthew Dillon 	return 0;
41521864bc5SMatthew Dillon }
41621864bc5SMatthew Dillon 
41721864bc5SMatthew Dillon 
41821864bc5SMatthew Dillon static int
devfs_dev_ioctl(struct dev_ioctl_args * ap)41921864bc5SMatthew Dillon devfs_dev_ioctl(struct dev_ioctl_args *ap)
42021864bc5SMatthew Dillon {
42121864bc5SMatthew Dillon 	int error;
4225704df1dSAlex Hornung 	struct devfs_rule_ioctl *rule;
42321864bc5SMatthew Dillon 
42421864bc5SMatthew Dillon 	error = 0;
4255704df1dSAlex Hornung 	rule = (struct devfs_rule_ioctl *)ap->a_data;
42621864bc5SMatthew Dillon 
42721864bc5SMatthew Dillon 	switch(ap->a_cmd) {
42821864bc5SMatthew Dillon 	case DEVFS_RULE_ADD:
429dd8bea0aSAlex Hornung 		error = devfs_rule_insert(rule);
43021864bc5SMatthew Dillon 		break;
43121864bc5SMatthew Dillon 
43221864bc5SMatthew Dillon 	case DEVFS_RULE_APPLY:
433dd8bea0aSAlex Hornung 		if (rule->mntpoint == NULL)
434dd8bea0aSAlex Hornung 			error = EINVAL;
435dd8bea0aSAlex Hornung 		else
4365704df1dSAlex Hornung 			devfs_apply_rules(rule->mntpoint);
43721864bc5SMatthew Dillon 		break;
43821864bc5SMatthew Dillon 
43921864bc5SMatthew Dillon 	case DEVFS_RULE_CLEAR:
440dd8bea0aSAlex Hornung 		error = devfs_rule_clear(rule);
44121864bc5SMatthew Dillon 		break;
44221864bc5SMatthew Dillon 
44321864bc5SMatthew Dillon 	case DEVFS_RULE_RESET:
444dd8bea0aSAlex Hornung 		if (rule->mntpoint == NULL)
445dd8bea0aSAlex Hornung 			error = EINVAL;
446dd8bea0aSAlex Hornung 		else
4475704df1dSAlex Hornung 			devfs_reset_rules(rule->mntpoint);
44821864bc5SMatthew Dillon 		break;
44921864bc5SMatthew Dillon 
45021864bc5SMatthew Dillon 	default:
45121864bc5SMatthew Dillon 		error = ENOTTY; /* Inappropriate ioctl for device */
45221864bc5SMatthew Dillon 		break;
45321864bc5SMatthew Dillon 	}
45421864bc5SMatthew Dillon 
45521864bc5SMatthew Dillon 	return(error);
45621864bc5SMatthew Dillon }
45721864bc5SMatthew Dillon 
45821864bc5SMatthew Dillon 
45921864bc5SMatthew Dillon static void
devfs_dev_init(void * unused)46021864bc5SMatthew Dillon devfs_dev_init(void *unused)
46121864bc5SMatthew Dillon {
46221864bc5SMatthew Dillon 	lockinit(&devfs_rule_lock, "devfs_rule lock", 0, 0);
46321864bc5SMatthew Dillon 
46421864bc5SMatthew Dillon 	devfs_rule_cache = objcache_create("devfs-rule-cache", 0, 0,
46521864bc5SMatthew Dillon 					   NULL, NULL, NULL,
46621864bc5SMatthew Dillon 					   objcache_malloc_alloc,
46721864bc5SMatthew Dillon 					   objcache_malloc_free,
46821864bc5SMatthew Dillon 					   &devfs_rule_malloc_args);
46921864bc5SMatthew Dillon 
4707cf221aeSAaron LI 	devfs_dev = make_dev(&devfs_dev_ops, 0, UID_ROOT, GID_WHEEL,
4717cf221aeSAaron LI 			     0600, "devfs");
47221864bc5SMatthew Dillon }
47321864bc5SMatthew Dillon 
47421864bc5SMatthew Dillon 
47521864bc5SMatthew Dillon static void
devfs_dev_uninit(void * unused)47621864bc5SMatthew Dillon devfs_dev_uninit(void *unused)
47721864bc5SMatthew Dillon {
478894bbb25SAlex Hornung 	/* XXX: destroy all rules first */
47921864bc5SMatthew Dillon 	destroy_dev(devfs_dev);
48021864bc5SMatthew Dillon 	objcache_destroy(devfs_rule_cache);
48121864bc5SMatthew Dillon }
48221864bc5SMatthew Dillon 
48321864bc5SMatthew Dillon 
484f3f3eadbSSascha Wildner SYSINIT(devfsdev, SI_SUB_DRIVERS, SI_ORDER_FIRST, devfs_dev_init, NULL);
48521864bc5SMatthew Dillon SYSUNINIT(devfsdev, SI_SUB_DRIVERS, SI_ORDER_FIRST, devfs_dev_uninit, NULL);
48621864bc5SMatthew Dillon 
487