2 * Copyright (c) 2009 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/ioccom.h>
41 #include <sys/spinlock2.h>
42 #include <sys/fcntl.h>
43 #include <sys/device.h>
44 #include <sys/mount.h>
45 #include <vfs/devfs/devfs.h>
46 #include <vfs/devfs/devfs_rules.h>
48 MALLOC_DECLARE(M_DEVFS
);
51 static int WildCmp(const char *w
, const char *s
);
52 static int WildCaseCmp(const char *w
, const char *s
);
53 static int wildCmp(const char **mary
, int d
, const char *w
, const char *s
);
54 static int wildCaseCmp(const char **mary
, int d
, const char *w
, const char *s
);
56 static d_open_t devfs_dev_open
;
57 static d_close_t devfs_dev_close
;
58 static d_ioctl_t devfs_dev_ioctl
;
60 static struct devfs_rule
*devfs_rule_alloc(struct devfs_rule
*);
61 static void devfs_rule_free(struct devfs_rule
*);
62 static void devfs_rule_insert(struct devfs_rule
*);
63 static void devfs_rule_remove(struct devfs_rule
*);
64 static void devfs_rule_clear(struct devfs_rule
*);
66 static int devfs_rule_checkname(struct devfs_rule
*, struct devfs_node
*);
68 static struct objcache
*devfs_rule_cache
;
69 static struct lock devfs_rule_lock
;
71 static struct objcache_malloc_args devfs_rule_malloc_args
= {
72 sizeof(struct devfs_rule
), M_DEVFS
};
74 static cdev_t devfs_dev
;
75 static struct devfs_rule_head devfs_rule_list
= TAILQ_HEAD_INITIALIZER(devfs_rule_list
);
77 static struct dev_ops devfs_dev_ops
= {
79 .d_open
= devfs_dev_open
,
80 .d_close
= devfs_dev_close
,
81 .d_ioctl
= devfs_dev_ioctl
85 static struct devfs_rule
*
86 devfs_rule_alloc(struct devfs_rule
*templ
)
88 struct devfs_rule
*rule
;
90 rule
= objcache_get(devfs_rule_cache
, M_WAITOK
);
91 memset(rule
, 0, sizeof(struct devfs_rule
));
93 if (templ
->mntpoint
!= NULL
) {
94 rule
->mntpoint
= kmalloc(templ
->mntpointlen
+1, M_DEVFS
, M_WAITOK
);
95 copyin(templ
->mntpoint
, rule
->mntpoint
, templ
->mntpointlen
+1);
98 if (templ
->name
!= NULL
) {
99 rule
->name
= kmalloc(templ
->namlen
+1, M_DEVFS
, M_WAITOK
);
100 copyin(templ
->name
, rule
->name
, templ
->namlen
+1);
103 if (templ
->linkname
!= NULL
) {
104 rule
->linkname
= kmalloc(templ
->linknamlen
+1, M_DEVFS
, M_WAITOK
);
105 copyin(templ
->linkname
, rule
->linkname
, templ
->linknamlen
+1);
108 rule
->rule_type
= templ
->rule_type
;
109 rule
->dev_type
= templ
->dev_type
;
110 rule
->mode
= templ
->mode
;
111 rule
->uid
= templ
->uid
;
112 rule
->gid
= templ
->gid
;
119 devfs_rule_free(struct devfs_rule
*rule
)
121 if (rule
->mntpoint
!= NULL
) {
122 kfree(rule
->mntpoint
, M_DEVFS
);
125 if (rule
->name
!= NULL
) {
126 kfree(rule
->name
, M_DEVFS
);
129 if (rule
->linkname
!= NULL
) {
130 kfree(rule
->linkname
, M_DEVFS
);
132 objcache_put(devfs_rule_cache
, rule
);
137 devfs_rule_insert(struct devfs_rule
*templ
)
139 struct devfs_rule
*rule
;
141 rule
= devfs_rule_alloc(templ
);
143 lockmgr(&devfs_rule_lock
, LK_EXCLUSIVE
);
144 TAILQ_INSERT_TAIL(&devfs_rule_list
, rule
, link
);
145 lockmgr(&devfs_rule_lock
, LK_RELEASE
);
150 devfs_rule_remove(struct devfs_rule
*rule
)
152 TAILQ_REMOVE(&devfs_rule_list
, rule
, link
);
153 devfs_rule_free(rule
);
158 devfs_rule_clear(struct devfs_rule
*templ
)
160 struct devfs_rule
*rule
, *rule1
, *rule2
;
162 rule
= devfs_rule_alloc(templ
);
164 lockmgr(&devfs_rule_lock
, LK_EXCLUSIVE
);
165 TAILQ_FOREACH_MUTABLE(rule1
, &devfs_rule_list
, link
, rule2
) {
166 if ((rule
->mntpoint
[0] == '*') ||
167 ( (rule
->mntpointlen
== rule1
->mntpointlen
) &&
168 (!memcmp(rule
->mntpoint
, rule1
->mntpoint
, rule
->mntpointlen
)) )) {
169 devfs_rule_remove(rule1
);
172 lockmgr(&devfs_rule_lock
, LK_RELEASE
);
173 devfs_rule_free(rule
);
178 devfs_rule_reset_node(struct devfs_node
*node
)
180 node
->flags
&= ~DEVFS_HIDDEN
;
182 if ((node
->node_type
== Pdev
) && (node
->d_dev
)) {
183 node
->uid
= node
->d_dev
->si_uid
;
184 node
->gid
= node
->d_dev
->si_gid
;
185 node
->mode
= node
->d_dev
->si_perms
;
193 devfs_rule_check_apply(struct devfs_node
*node
)
195 struct devfs_rule
*rule
;
196 struct mount
*mp
= node
->mp
;
200 /* Check if it is locked already. if not, we acquire the devfs lock */
201 if (!(lockstatus(&devfs_rule_lock
, curthread
)) == LK_EXCLUSIVE
) {
202 lockmgr(&devfs_rule_lock
, LK_EXCLUSIVE
);
206 TAILQ_FOREACH(rule
, &devfs_rule_list
, link
) {
209 * Skip this rule if it is only intended for jailed mount points
210 * and the current mount point isn't jailed
212 if ((rule
->rule_type
& DEVFS_RULE_JAIL
) &&
213 (!(DEVFS_MNTDATA(mp
)->jailed
)) )
217 * Skip this rule if the mount point specified in the rule doesn't
218 * match the mount point of the node
220 if ((rule
->mntpoint
[0] != '*') &&
221 ((rule
->mntpointlen
!= DEVFS_MNTDATA(mp
)->mntonnamelen
) ||
222 (memcmp(rule
->mntpoint
, mp
->mnt_stat
.f_mntonname
, rule
->mntpointlen
))))
226 * Skip this rule if this is a by-type rule and the device flags
227 * don't match the specified device type in the rule
229 if ((rule
->rule_type
& DEVFS_RULE_TYPE
) &&
230 ( (rule
->dev_type
== 0) || (!dev_is_good(node
->d_dev
)) ||
231 (!(dev_dflags(node
->d_dev
) & rule
->dev_type
))) )
235 * Skip this rule if this is a by-name rule and the node name
236 * doesn't match the wildcard string in the rule
238 if ((rule
->rule_type
& DEVFS_RULE_NAME
) &&
239 (!devfs_rule_checkname(rule
, node
)) )
243 if (rule
->rule_type
& DEVFS_RULE_HIDE
) {
245 * If we should hide the device, we just apply the relevant
246 * hide flag to the node and let devfs do the rest in the
249 node
->flags
|= DEVFS_HIDDEN
;
251 } else if (rule
->rule_type
& DEVFS_RULE_SHOW
) {
253 * Show rule just means that the node should not be hidden, so
254 * what we do is clear the hide flag from the node.
256 node
->flags
&= ~DEVFS_HIDDEN
;
258 } else if ((rule
->rule_type
& DEVFS_RULE_LINK
) && (node
->node_type
!= Plink
)) {
260 * This is a LINK rule, so we tell devfs to create
261 * a link with the correct name to this node.
263 devfs_alias_create(rule
->linkname
, node
);
267 * This is a normal ownership/permission rule. We
268 * just apply the permissions and ownership and
271 node
->mode
= rule
->mode
;
272 node
->uid
= rule
->uid
;
273 node
->gid
= rule
->gid
;
278 /* If we acquired the lock, we also get rid of it */
280 lockmgr(&devfs_rule_lock
, LK_RELEASE
);
287 devfs_rule_checkname(struct devfs_rule
*rule
, struct devfs_node
*node
)
289 struct devfs_node
*parent
= DEVFS_MNTDATA(node
->mp
)->root_node
;
291 char *name
, name_buf
[PATH_MAX
];
294 devfs_resolve_name_path(rule
->name
, name_buf
, &path
, &name
);
295 parent
= devfs_resolve_or_create_path(parent
, path
, 0);
298 return 0; /* no match */
300 /* Check if node is a child of the parent we found */
301 if (node
->parent
!= parent
)
302 return 0; /* no match */
304 if (rule
->rule_type
& DEVFS_RULE_LINK
)
305 no_match
= memcmp(name
, node
->d_dir
.d_name
, strlen(name
));
307 no_match
= WildCaseCmp(name
, node
->d_dir
.d_name
);
314 devfs_dev_open(struct dev_open_args
*ap
)
317 * Only allow read-write access.
319 if (((ap
->a_oflags
& FWRITE
) == 0) || ((ap
->a_oflags
& FREAD
) == 0))
323 * We don't allow nonblocking access.
325 if ((ap
->a_oflags
& O_NONBLOCK
) != 0) {
326 devfs_debug(DEVFS_DEBUG_DEBUG
, "devfs_dev: can't do nonblocking access\n");
335 devfs_dev_close(struct dev_close_args
*ap
)
342 devfs_dev_ioctl(struct dev_ioctl_args
*ap
)
345 struct devfs_rule
*rule
;
346 char mntpoint
[PATH_MAX
+1];
349 rule
= (struct devfs_rule
*)ap
->a_data
;
353 devfs_rule_insert(rule
);
356 case DEVFS_RULE_APPLY
:
357 copyin(rule
->mntpoint
, mntpoint
, rule
->mntpointlen
);
358 devfs_apply_rules(mntpoint
);
361 case DEVFS_RULE_CLEAR
:
362 devfs_rule_clear(rule
);
365 case DEVFS_RULE_RESET
:
366 copyin(rule
->mntpoint
, mntpoint
, rule
->mntpointlen
);
367 devfs_reset_rules(mntpoint
);
371 error
= ENOTTY
; /* Inappropriate ioctl for device */
380 devfs_dev_init(void *unused
)
382 lockinit(&devfs_rule_lock
, "devfs_rule lock", 0, 0);
384 devfs_rule_cache
= objcache_create("devfs-rule-cache", 0, 0,
386 objcache_malloc_alloc
,
387 objcache_malloc_free
,
388 &devfs_rule_malloc_args
);
390 devfs_dev
= make_dev(&devfs_dev_ops
,
400 devfs_dev_uninit(void *unused
)
402 /* XXX: destroy all rules first */
403 destroy_dev(devfs_dev
);
404 objcache_destroy(devfs_rule_cache
);
408 SYSINIT(devfsdev
,SI_SUB_DRIVERS
,SI_ORDER_FIRST
,devfs_dev_init
,NULL
)
409 SYSUNINIT(devfsdev
, SI_SUB_DRIVERS
,SI_ORDER_FIRST
,devfs_dev_uninit
, NULL
);
414 WildCmp(const char *w
, const char *s
)
418 int slen
= strlen(s
);
421 for (i
= c
= 0; w
[i
]; ++i
) {
425 mary
= kmalloc(sizeof(char *) * (c
+ 1), M_DEVFS
, M_WAITOK
);
426 for (i
= 0; i
< c
; ++i
)
428 i
= wildCmp(mary
, 0, w
, s
);
429 kfree(mary
, M_DEVFS
);
434 WildCaseCmp(const char *w
, const char *s
)
438 int slen
= strlen(s
);
441 for (i
= c
= 0; w
[i
]; ++i
) {
445 mary
= kmalloc(sizeof(char *) * (c
+ 1), M_DEVFS
, M_WAITOK
);
446 for (i
= 0; i
< c
; ++i
)
448 i
= wildCaseCmp(mary
, 0, w
, s
);
449 kfree(mary
, M_DEVFS
);
454 * WildCmp() - compare wild string to sane string
456 * Returns 0 on success, -1 on failure.
459 wildCmp(const char **mary
, int d
, const char *w
, const char *s
)
470 * optimize terminator
474 if (w
[1] != '?' && w
[1] != '*') {
476 * optimize * followed by non-wild
478 for (i
= 0; s
+ i
< mary
[d
]; ++i
) {
479 if (s
[i
] == w
[1] && wildCmp(mary
, d
+ 1, w
+ 1, s
+ i
) == 0)
486 for (i
= 0; s
+ i
< mary
[d
]; ++i
) {
487 if (wildCmp(mary
, d
+ 1, w
+ 1, s
+ i
) == 0)
502 if (*w
== 0) /* terminator */
515 * WildCaseCmp() - compare wild string to sane string, case insensitive
517 * Returns 0 on success, -1 on failure.
520 wildCaseCmp(const char **mary
, int d
, const char *w
, const char *s
)
531 * optimize terminator
535 if (w
[1] != '?' && w
[1] != '*') {
537 * optimize * followed by non-wild
539 for (i
= 0; s
+ i
< mary
[d
]; ++i
) {
540 if (s
[i
] == w
[1] && wildCaseCmp(mary
, d
+ 1, w
+ 1, s
+ i
) == 0)
547 for (i
= 0; s
+ i
< mary
[d
]; ++i
) {
548 if (wildCaseCmp(mary
, d
+ 1, w
+ 1, s
+ i
) == 0)
562 #define tolower(x) ((x >= 'A' && x <= 'Z')?(x+('a'-'A')):(x))
563 if (tolower(*w
) != tolower(*s
))
566 if (*w
== 0) /* terminator */