DEVFS - Cleanup of dead functions/comments; various fixes
[dragonfly.git] / sys / vfs / devfs / devfs_rules.c
blob385796c8de4a2cdc5d379ec005b9c8ff6ef22122
1 /*
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
9 * are met:
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
16 * distribution.
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
32 * SUCH DAMAGE.
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>
40 #include <sys/lock.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 = {
78 { "devfs", 0, 0 },
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;
114 return rule;
118 static void
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);
136 static void
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);
149 static void
150 devfs_rule_remove(struct devfs_rule *rule)
152 TAILQ_REMOVE(&devfs_rule_list, rule, link);
153 devfs_rule_free(rule);
157 static void
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;
188 return 0;
193 devfs_rule_check_apply(struct devfs_node *node)
195 struct devfs_rule *rule;
196 struct mount *mp = node->mp;
197 int applies = 0;
198 int locked = 0;
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);
203 locked = 1;
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)) )
214 continue;
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))))
223 continue;
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))) )
232 continue;
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)) )
240 continue;
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
247 * vnops
249 node->flags |= DEVFS_HIDDEN;
250 applies = 1;
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;
257 applies = 1;
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);
264 applies = 1;
265 } else {
267 * This is a normal ownership/permission rule. We
268 * just apply the permissions and ownership and
269 * we are done.
271 node->mode = rule->mode;
272 node->uid = rule->uid;
273 node->gid = rule->gid;
274 applies = 1;
278 /* If we acquired the lock, we also get rid of it */
279 if (locked)
280 lockmgr(&devfs_rule_lock, LK_RELEASE);
282 return applies;
286 static int
287 devfs_rule_checkname(struct devfs_rule *rule, struct devfs_node *node)
289 struct devfs_node *parent = DEVFS_MNTDATA(node->mp)->root_node;
290 char *path = NULL;
291 char *name, name_buf[PATH_MAX];
292 int no_match = 0;
294 devfs_resolve_name_path(rule->name, name_buf, &path, &name);
295 parent = devfs_resolve_or_create_path(parent, path, 0);
297 if (parent == NULL)
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));
306 else
307 no_match = WildCaseCmp(name, node->d_dir.d_name);
309 return !no_match;
313 static int
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))
320 return(EPERM);
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");
327 return(ENODEV);
330 return 0;
334 static int
335 devfs_dev_close(struct dev_close_args *ap)
337 return 0;
341 static int
342 devfs_dev_ioctl(struct dev_ioctl_args *ap)
344 int error;
345 struct devfs_rule *rule;
346 char mntpoint[PATH_MAX+1];
348 error = 0;
349 rule = (struct devfs_rule *)ap->a_data;
351 switch(ap->a_cmd) {
352 case DEVFS_RULE_ADD:
353 devfs_rule_insert(rule);
354 break;
356 case DEVFS_RULE_APPLY:
357 copyin(rule->mntpoint, mntpoint, rule->mntpointlen);
358 devfs_apply_rules(mntpoint);
359 break;
361 case DEVFS_RULE_CLEAR:
362 devfs_rule_clear(rule);
363 break;
365 case DEVFS_RULE_RESET:
366 copyin(rule->mntpoint, mntpoint, rule->mntpointlen);
367 devfs_reset_rules(mntpoint);
368 break;
370 default:
371 error = ENOTTY; /* Inappropriate ioctl for device */
372 break;
375 return(error);
379 static void
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,
385 NULL, NULL, NULL,
386 objcache_malloc_alloc,
387 objcache_malloc_free,
388 &devfs_rule_malloc_args );
390 devfs_dev = make_dev(&devfs_dev_ops,
392 UID_ROOT,
393 GID_WHEEL,
394 0600,
395 "devfs");
399 static void
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);
413 static int
414 WildCmp(const char *w, const char *s)
416 int i;
417 int c;
418 int slen = strlen(s);
419 const char **mary;
421 for (i = c = 0; w[i]; ++i) {
422 if (w[i] == '*')
423 ++c;
425 mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
426 for (i = 0; i < c; ++i)
427 mary[i] = s + slen;
428 i = wildCmp(mary, 0, w, s);
429 kfree(mary, M_DEVFS);
430 return(i);
433 static int
434 WildCaseCmp(const char *w, const char *s)
436 int i;
437 int c;
438 int slen = strlen(s);
439 const char **mary;
441 for (i = c = 0; w[i]; ++i) {
442 if (w[i] == '*')
443 ++c;
445 mary = kmalloc(sizeof(char *) * (c + 1), M_DEVFS, M_WAITOK);
446 for (i = 0; i < c; ++i)
447 mary[i] = s + slen;
448 i = wildCaseCmp(mary, 0, w, s);
449 kfree(mary, M_DEVFS);
450 return(i);
454 * WildCmp() - compare wild string to sane string
456 * Returns 0 on success, -1 on failure.
458 static int
459 wildCmp(const char **mary, int d, const char *w, const char *s)
461 int i;
464 * skip fixed portion
466 for (;;) {
467 switch(*w) {
468 case '*':
470 * optimize terminator
472 if (w[1] == 0)
473 return(0);
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)
480 return(0);
482 } else {
484 * less-optimal
486 for (i = 0; s + i < mary[d]; ++i) {
487 if (wildCmp(mary, d + 1, w + 1, s + i) == 0)
488 return(0);
491 mary[d] = s;
492 return(-1);
493 case '?':
494 if (*s == 0)
495 return(-1);
496 ++w;
497 ++s;
498 break;
499 default:
500 if (*w != *s)
501 return(-1);
502 if (*w == 0) /* terminator */
503 return(0);
504 ++w;
505 ++s;
506 break;
509 /* not reached */
510 return(-1);
515 * WildCaseCmp() - compare wild string to sane string, case insensitive
517 * Returns 0 on success, -1 on failure.
519 static int
520 wildCaseCmp(const char **mary, int d, const char *w, const char *s)
522 int i;
525 * skip fixed portion
527 for (;;) {
528 switch(*w) {
529 case '*':
531 * optimize terminator
533 if (w[1] == 0)
534 return(0);
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)
541 return(0);
543 } else {
545 * less-optimal
547 for (i = 0; s + i < mary[d]; ++i) {
548 if (wildCaseCmp(mary, d + 1, w + 1, s + i) == 0)
549 return(0);
552 mary[d] = s;
553 return(-1);
554 case '?':
555 if (*s == 0)
556 return(-1);
557 ++w;
558 ++s;
559 break;
560 default:
561 if (*w != *s) {
562 #define tolower(x) ((x >= 'A' && x <= 'Z')?(x+('a'-'A')):(x))
563 if (tolower(*w) != tolower(*s))
564 return(-1);
566 if (*w == 0) /* terminator */
567 return(0);
568 ++w;
569 ++s;
570 break;
573 /* not reached */
574 return(-1);