.gitignore: properly spell cscope, add empty vim swap files
[dragonfly.git] / usr.sbin / devfsctl / devfsctl.c
blob0b1f23b0e27e288a7f16147dde301ede8ba5b0c2
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/ioctl.h>
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <err.h>
42 #include <pwd.h>
43 #include <grp.h>
44 #include <vfs/devfs/devfs_rules.h>
45 #include <sys/device.h>
47 void dump_config(void);
48 void rule_init(struct devfs_rule *rule, char *name);
49 int rule_check_num_args(char **tokens, int num);
50 void rule_group(char **tokens);
51 void rule_parse_groups(void);
52 void rule_clear_groups(void);
53 void rule_clear_rules(void);
54 void rule_perm(char **tokens);
55 void rule_link(char **tokens);
56 void rule_hide(char **tokens);
57 void rule_show(char **tokens);
58 struct devfs_rule *get_group(char *name);
59 struct devfs_rule *get_rule(char *name);
60 void put_rule(struct devfs_rule *rule);
61 int rule_open(void);
62 int rule_close(void);
63 int rule_ioctl(unsigned long cmd, struct devfs_rule *rule);
64 int read_config(char *name);
65 int process_line(FILE* fd);
66 void usage(void);
68 static int dev_fd;
69 static int jail = 0;
70 static struct devfs_rule dummy_rule;
71 static int verbose = 0;
74 TAILQ_HEAD(devfs_rule_head, devfs_rule);
76 static struct devfs_rule_head devfs_rule_list = TAILQ_HEAD_INITIALIZER(devfs_rule_list);
77 static struct devfs_rule_head devfs_group_list = TAILQ_HEAD_INITIALIZER(devfs_group_list);
80 void
81 dump_config(void)
83 struct devfs_rule *rule;
84 struct passwd *pwd;
85 struct group *grp;
87 TAILQ_FOREACH(rule, &devfs_rule_list, link) {
88 printf("-----------------------------------------\n");
89 printf("Affects:\t");
90 if (rule->dev_type) {
91 printf("device type ");
92 switch (rule->dev_type) {
93 case D_TAPE:
94 puts("D_TAPE");
95 break;
96 case D_DISK:
97 puts("D_DISK");
98 break;
99 case D_TTY:
100 puts("D_TTY");
101 break;
102 case D_MEM:
103 puts("D_MEM");
104 break;
105 default:
106 puts("*unknown");
108 } else {
109 printf("%s\n", rule->name);
112 printf("only jails?\t%s\n", (rule->rule_type & DEVFS_RULE_JAIL)?"yes":"no");
114 printf("Action:\t\t");
115 if (rule->rule_type & DEVFS_RULE_LINK) {
116 printf("link to %s\n", rule->linkname);
117 } else if (rule->rule_type & DEVFS_RULE_HIDE) {
118 printf("hide\n");
119 } else if (rule->rule_type & DEVFS_RULE_SHOW) {
120 printf("show\n");
121 } else {
122 pwd = getpwuid(rule->uid);
123 grp = getgrgid(rule->gid);
124 printf("set mode: %o\n\t\tset owner: %s\n\t\tset group: %s\n",
125 rule->mode, pwd->pw_name, grp->gr_name);
128 printf("-----------------------------------------\n");
131 void
132 rule_init(struct devfs_rule *rule, char *name)
134 size_t len;
136 if (!strcmp(name, "D_TAPE")) {
137 rule->rule_type = DEVFS_RULE_TYPE;
138 rule->dev_type = D_TAPE;
139 } else if (!strcmp(name, "D_DISK")) {
140 rule->rule_type = DEVFS_RULE_TYPE;
141 rule->dev_type = D_DISK;
142 } else if (!strcmp(name, "D_TTY")) {
143 rule->rule_type = DEVFS_RULE_TYPE;
144 rule->dev_type = D_TTY;
145 } else if (!strcmp(name, "D_MEM")) {
146 rule->rule_type = DEVFS_RULE_TYPE;
147 rule->dev_type = D_MEM;
148 } else {
149 len = strlen(name);
150 rule->namlen = len;
151 rule->name = malloc(len+1);
152 strlcpy(rule->name, name, len+1);
153 rule->rule_type = DEVFS_RULE_NAME;
156 if (jail)
157 rule->rule_type |= DEVFS_RULE_JAIL;
161 rule_check_num_args(char **tokens, int num)
163 int i = 0;
164 for (i = 0; tokens[i] != NULL; i++);
166 if (i != num) {
167 printf("This line in the configuration file is incorrect."
168 " It has %d words, but %d were expected\n",
169 i, num);
171 for (i = 0; *(tokens[i]); i++) {
172 puts(tokens[i]);
173 putchar('\t');
175 putchar('\n');
177 return 1;
179 return 0;
182 void
183 rule_group(char **tokens)
185 size_t len;
186 struct devfs_rule *group, *rule;
188 rule = get_rule(NULL);
189 rule_init(rule, tokens[0]);
191 if (!(group = get_group(tokens[2]))) {
192 group = get_rule(NULL);
193 len = strlen(tokens[2]);
194 group->namlen = len;
195 group->name = malloc(len+1);
196 strlcpy(group->name, tokens[2], len+1);
197 TAILQ_INSERT_TAIL(&devfs_group_list, group, link);
200 rule->group = group;
201 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
204 void
205 rule_parse_groups(void)
207 struct devfs_rule *rule, *group;
209 TAILQ_FOREACH(rule, &devfs_rule_list, link) {
210 if ((group = rule->group)) {
211 rule->group = 0;
212 rule->rule_type |= group->rule_type;
213 rule->mode = group->mode;
214 rule->uid = group->uid;
215 rule->gid = group->gid;
217 if (group->linkname) {
218 rule->linknamlen = group->linknamlen;
219 rule->linkname = malloc(group->linknamlen+1);
220 strlcpy(rule->linkname, group->linkname, group->linknamlen+1);
226 void
227 rule_clear_groups(void)
229 struct devfs_rule *rule, *rule1;
230 TAILQ_FOREACH_MUTABLE(rule, &devfs_group_list, link, rule1) {
231 TAILQ_REMOVE(&devfs_group_list, rule, link);
232 put_rule(rule);
236 void
237 rule_clear_rules(void)
239 struct devfs_rule *rule, *rule1;
240 TAILQ_FOREACH_MUTABLE(rule, &devfs_rule_list, link, rule1) {
241 TAILQ_REMOVE(&devfs_rule_list, rule, link);
242 put_rule(rule);
246 void
247 rule_perm(char **tokens)
249 struct devfs_rule *rule;
250 struct passwd *pwd;
251 struct group *grp;
252 rule = get_rule(tokens[0]);
253 rule_init(rule, tokens[0]);
254 rule->mode = strtol(tokens[2], NULL, 8);
255 if ((pwd = getpwnam(tokens[3])))
256 rule->uid = pwd->pw_uid;
257 if ((grp = getgrnam(tokens[4])))
258 rule->gid = grp->gr_gid;
259 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
262 void
263 rule_link(char **tokens)
265 struct devfs_rule *rule;
266 size_t len;
268 rule = get_rule(tokens[0]);
269 rule_init(rule, tokens[0]);
271 len = strlen(tokens[2]);
272 rule->linknamlen = len;
273 rule->linkname = malloc(len+1);
274 strlcpy(rule->linkname, tokens[2], len+1);
275 rule->rule_type |= DEVFS_RULE_LINK;
277 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
280 void
281 rule_hide(char **tokens)
283 struct devfs_rule *rule;
285 rule = get_rule(tokens[0]);
286 rule_init(rule, tokens[0]);
288 rule->rule_type |= DEVFS_RULE_HIDE;
290 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
293 void
294 rule_show(char **tokens)
296 struct devfs_rule *rule;
298 rule = get_rule(tokens[0]);
299 rule_init(rule, tokens[0]);
301 rule->rule_type |= DEVFS_RULE_SHOW;
303 TAILQ_INSERT_TAIL(&devfs_rule_list, rule, link);
306 struct devfs_rule *
307 get_group(char *name)
309 struct devfs_rule *rule, *found = NULL;
311 TAILQ_FOREACH(rule, &devfs_group_list, link) {
312 if (!strcmp(rule->name, name)) {
313 found = rule;
314 break;
318 return found;
321 struct devfs_rule *
322 get_rule(char *name)
324 struct devfs_rule *rule;
326 if ((name == NULL) || (!(rule = get_group(name)))) {
327 rule = (struct devfs_rule *)malloc(sizeof(struct devfs_rule));
328 memset(rule, 0, sizeof(struct devfs_rule));
331 return rule;
334 void
335 put_rule(struct devfs_rule *rule)
337 if (rule->name)
338 free(rule->name);
340 if (rule->linkname)
341 free(rule->linkname);
343 if (rule->mntpoint)
344 free(rule->mntpoint);
346 free(rule);
350 rule_open(void)
352 if ((dev_fd = open("/dev/devfs", O_RDWR)) == -1) {
353 perror("open /dev/devfs error\n");
354 return 1;
357 return 0;
361 rule_close(void)
363 close(dev_fd);
364 return 0;
368 rule_ioctl(unsigned long cmd, struct devfs_rule *rule)
370 if (ioctl(dev_fd, cmd, rule) == -1) {
371 perror("ioctl error");
372 return 1;
375 return 0;
379 read_config(char *name)
381 FILE *fd;
382 if ((fd = fopen(name, "r")) == NULL) {
383 printf("Error opening config file %s\n", name);
384 perror("fopen");
385 return 1;
388 while (process_line(fd) == 0);
389 rule_parse_groups();
391 fclose(fd);
393 return 0;
397 process_line(FILE* fd)
399 char buffer[4096];
400 char *tokens[256];
401 int c, n, i = 0;
402 int ret = 0;
405 while (((c = fgetc(fd)) != EOF) && (c != '\n')) {
406 buffer[i++] = (char)c;
407 if (i == (sizeof(buffer) -1))
408 break;
410 buffer[i] = '\0';
411 if (feof(fd) || ferror(fd))
412 ret = 1;
413 c = 0;
414 while (((buffer[c] == ' ') || (buffer[c] == '\t')) && (c < i)) c++;
415 tokens[0] = &buffer[c];
416 for (n = 1, c = 0; c < i; c++) {
417 if ((buffer[c] == ' ') || (buffer[c] == '\t')) {
418 buffer[c++] = '\0';
419 while (((buffer[c] == ' ') || (buffer[c] == '\t')) && (c < i)) c++;
420 tokens[n++] = &buffer[c];
423 tokens[n] = NULL;
425 if (n < 2)
426 return ret;
428 if (verbose)
429 printf("Currently processing verb/command: %s\n", (tokens[0][0] == '#')?(tokens[0]):(tokens[1]));
431 if (!strcmp(tokens[0], "#include")) {
432 /* This is an include instruction */
433 if (!rule_check_num_args(tokens, 2))
434 read_config(tokens[1]);
435 } else if (!strcmp(tokens[0], "#jail")) {
436 /* This is a jail instruction */
437 if (!rule_check_num_args(tokens, 2))
438 jail = (tokens[1][0] == 'y')?1:0;
439 } else if (!strcmp(tokens[1], "group")) {
440 /* This is a group rule */
441 if (!rule_check_num_args(tokens, 3))
442 rule_group(tokens);
443 } else if (!strcmp(tokens[1], "perm")) {
444 /* This is a perm rule */
445 if (!rule_check_num_args(tokens, 5))
446 rule_perm(tokens);
447 } else if (!strcmp(tokens[1], "link")) {
448 /* This is a link rule */
449 if (!rule_check_num_args(tokens, 3))
450 rule_link(tokens);
451 } else if (!strcmp(tokens[1], "hide")) {
452 /* This is a hide rule */
453 if (!rule_check_num_args(tokens, 2))
454 rule_hide(tokens);
455 } else if (!strcmp(tokens[1], "show")) {
456 /* This is a show rule */
457 if (!rule_check_num_args(tokens, 2))
458 rule_show(tokens);
459 } else {
460 printf("Unknown verb %s\n", tokens[1]);
462 return ret;
466 void
467 usage(void)
469 printf("Usage: devfsctl <commands> [options]\n");
470 printf("Valid commands are:\n");
471 printf(" -a\n\t Loads all read rules into the kernel and "
472 "applies them\n");
473 printf(" -c\n\t Clears all rules stored in the kernel but "
474 "does not reset the nodes\n");
475 printf(" -d\n\t Dumps the rules that have been loaded to the "
476 "screen to verify syntax\n");
477 printf(" -r\n\t Resets all devfs_nodes but does not clear "
478 "the rules stored\n");
480 printf("\nValid options and its arguments are:\n");
481 printf(" -f <config_file>\n\t Specifies the configuration file "
482 "to be used\n");
483 printf(" -m <mount_point>\n\t Specifies a mount point to which "
484 "the command will apply. Defaults to *\n");
485 printf(" -v\n\t Enables verbose mode\n");
487 exit(1);
491 int main(int argc, char *argv[])
493 struct devfs_rule *rule;
494 int ch, done = 0;
495 size_t len;
496 char farg[1024], marg[1024];
497 int fflag = 0, dflag = 0, mflag = 0;
498 int aflag = 0, cflag = 0, rflag = 0;
500 while ((ch = getopt(argc, argv, "acdf:hrvm:")) != -1) {
501 switch (ch) {
502 case 'v':
503 verbose = 1;
504 break;
505 case 'f':
506 strlcpy(farg, optarg, 1024);
507 fflag = 1;
508 break;
509 case 'm':
510 strlcpy(marg, optarg, 1024);
511 mflag = 1;
512 break;
513 case 'a':
514 aflag = 1;
515 break;
516 case 'c':
517 cflag = 1;
518 break;
519 case 'r':
520 rflag = 1;
521 break;
522 case 'd':
523 dflag = 1;
524 break;
525 case 'h':
526 case '?':
527 default:
528 usage();
532 argc -= optind;
533 argv += optind;
535 if (!mflag)
536 strcpy(marg, "*");
538 if (cflag) {
539 done = 1;
540 len = strlen(marg);
541 dummy_rule.mntpoint = malloc(len+1);
542 strlcpy(dummy_rule.mntpoint, marg, len+1);
543 dummy_rule.mntpointlen = len;
545 rule_open();
546 rule_ioctl(DEVFS_RULE_CLEAR, &dummy_rule);
547 rule_close();
550 if (rflag) {
551 done = 1;
552 len = strlen(marg);
553 dummy_rule.mntpoint = malloc(len+1);
554 strlcpy(dummy_rule.mntpoint, marg, len+1);
555 dummy_rule.mntpointlen = len;
556 rule_open();
557 rule_ioctl(DEVFS_RULE_RESET, &dummy_rule);
558 rule_close();
561 if (fflag) {
562 jail = 0;
563 read_config(farg);
566 if (dflag) {
567 done = 1;
568 dump_config();
571 if (aflag) {
572 done = 1;
573 jail = 0;
574 #if 0
575 read_config(farg);
576 #endif
577 rule_open();
578 len = strlen(marg);
580 TAILQ_FOREACH(rule, &devfs_rule_list, link) {
581 rule->mntpoint = malloc(len+1);
582 strlcpy(rule->mntpoint, marg, len+1);
583 rule->mntpointlen = len;
584 rule_ioctl(DEVFS_RULE_ADD, rule);
587 dummy_rule.mntpoint = malloc(len+1);
588 strlcpy(dummy_rule.mntpoint, marg, len+1);
589 dummy_rule.mntpointlen = len;
590 rule_ioctl(DEVFS_RULE_APPLY, &dummy_rule);
592 rule_close();
593 rule_clear_groups();
594 rule_clear_rules();
597 if (!done)
598 usage();
600 return 0;