2 * Copyright (C) 2003,2004 Greg Kroah-Hartman <greg@kroah.com>
3 * Copyright (C) 2003-2006 Kay Sievers <kay.sievers@vrfy.org>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation version 2 of the License.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32 #include "udev_rules.h"
33 #include "udev_selinux.h"
36 void udev_rules_iter_init(struct udev_rules *rules)
38 dbg(rules->udev, "bufsize=%zi\n", rules->bufsize);
42 struct udev_rule *udev_rules_iter_next(struct udev_rules *rules)
44 struct udev_rule *rule;
49 dbg(rules->udev, "current=%zi\n", rules->current);
50 if (rules->current >= rules->bufsize) {
51 dbg(rules->udev, "no more rules\n");
56 rule = (struct udev_rule *) (rules->buf + rules->current);
57 rules->current += sizeof(struct udev_rule) + rule->bufsize;
62 struct udev_rule *udev_rules_iter_label(struct udev_rules *rules, const char *label)
64 struct udev_rule *rule;
65 size_t start = rules->current;
68 dbg(rules->udev, "current=%zi\n", rules->current);
69 if (rules->current >= rules->bufsize) {
70 err(rules->udev, "LABEL='%s' not found, GOTO will be ignored\n", label);
71 rules->current = start;
74 rule = (struct udev_rule *) (rules->buf + rules->current);
76 if (strcmp(&rule->buf[rule->label.val_off], label) != 0) {
77 dbg(rules->udev, "moving forward, looking for label '%s'\n", label);
78 rules->current += sizeof(struct udev_rule) + rule->bufsize;
82 dbg(rules->udev, "found label '%s'\n", label);
86 static int get_key(struct udev_rules *rules, char **line, char **key, enum key_operation *operation, char **value)
92 if (linepos == NULL && linepos[0] == '\0')
96 while (isspace(linepos[0]) || linepos[0] == ',')
100 if (linepos[0] == '\0')
106 if (linepos[0] == '\0')
108 if (isspace(linepos[0]))
110 if (linepos[0] == '=')
112 if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
113 if (linepos[1] == '=')
117 /* remember end of key */
120 /* skip whitespace after key */
121 while (isspace(linepos[0]))
123 if (linepos[0] == '\0')
126 /* get operation type */
127 if (linepos[0] == '=' && linepos[1] == '=') {
128 *operation = KEY_OP_MATCH;
130 dbg(rules->udev, "operator=match\n");
131 } else if (linepos[0] == '!' && linepos[1] == '=') {
132 *operation = KEY_OP_NOMATCH;
134 dbg(rules->udev, "operator=nomatch\n");
135 } else if (linepos[0] == '+' && linepos[1] == '=') {
136 *operation = KEY_OP_ADD;
138 dbg(rules->udev, "operator=add\n");
139 } else if (linepos[0] == '=') {
140 *operation = KEY_OP_ASSIGN;
142 dbg(rules->udev, "operator=assign\n");
143 } else if (linepos[0] == ':' && linepos[1] == '=') {
144 *operation = KEY_OP_ASSIGN_FINAL;
146 dbg(rules->udev, "operator=assign_final\n");
152 dbg(rules->udev, "key='%s'\n", *key);
154 /* skip whitespace after operator */
155 while (isspace(linepos[0]))
157 if (linepos[0] == '\0')
161 if (linepos[0] == '"')
167 temp = strchr(linepos, '"');
172 dbg(rules->udev, "value='%s'\n", *value);
174 /* move line to next key */
180 /* extract possible KEY{attr} */
181 static char *get_key_attribute(struct udev_rules *rules, char *str)
186 attr = strchr(str, '{');
189 pos = strchr(attr, '}');
191 err(rules->udev, "missing closing brace for format\n");
195 dbg(rules->udev, "attribute='%s'\n", attr);
202 static int add_rule_key(struct udev_rule *rule, struct key *key,
203 enum key_operation operation, const char *value)
205 size_t val_len = strnlen(value, PATH_SIZE);
207 key->operation = operation;
209 key->val_off = rule->bufsize;
210 strlcpy(rule->buf + rule->bufsize, value, val_len+1);
211 rule->bufsize += val_len+1;
216 static int add_rule_key_pair(struct udev_rules *rules, struct udev_rule *rule, struct key_pairs *pairs,
217 enum key_operation operation, const char *key, const char *value)
219 size_t key_len = strnlen(key, PATH_SIZE);
221 if (pairs->count >= PAIRS_MAX) {
222 err(rules->udev, "skip, too many keys of the same type in a single rule\n");
226 add_rule_key(rule, &pairs->keys[pairs->count].key, operation, value);
228 /* add the key-name of the pair */
229 pairs->keys[pairs->count].key_name_off = rule->bufsize;
230 strlcpy(rule->buf + rule->bufsize, key, key_len+1);
231 rule->bufsize += key_len+1;
238 static int add_to_rules(struct udev_rules *rules, char *line, const char *filename, unsigned int lineno)
240 char buf[sizeof(struct udev_rule) + LINE_SIZE];
241 struct udev_rule *rule;
250 memset(buf, 0x00, sizeof(buf));
251 rule = (struct udev_rule *) buf;
252 rule->event_timeout = -1;
256 /* get all the keys */
260 enum key_operation operation = KEY_OP_UNSET;
262 retval = get_key(rules, &linepos, &key, &operation, &value);
266 if (strcasecmp(key, "ACTION") == 0) {
267 if (operation != KEY_OP_MATCH &&
268 operation != KEY_OP_NOMATCH) {
269 err(rules->udev, "invalid ACTION operation\n");
272 add_rule_key(rule, &rule->action, operation, value);
277 if (strcasecmp(key, "DEVPATH") == 0) {
278 if (operation != KEY_OP_MATCH &&
279 operation != KEY_OP_NOMATCH) {
280 err(rules->udev, "invalid DEVPATH operation\n");
283 add_rule_key(rule, &rule->devpath, operation, value);
288 if (strcasecmp(key, "KERNEL") == 0) {
289 if (operation != KEY_OP_MATCH &&
290 operation != KEY_OP_NOMATCH) {
291 err(rules->udev, "invalid KERNEL operation\n");
294 add_rule_key(rule, &rule->kernel, operation, value);
299 if (strcasecmp(key, "SUBSYSTEM") == 0) {
300 if (operation != KEY_OP_MATCH &&
301 operation != KEY_OP_NOMATCH) {
302 err(rules->udev, "invalid SUBSYSTEM operation\n");
305 /* bus, class, subsystem events should all be the same */
306 if (strcmp(value, "subsystem") == 0 ||
307 strcmp(value, "bus") == 0 ||
308 strcmp(value, "class") == 0) {
309 if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
310 err(rules->udev, "'%s' must be specified as 'subsystem' \n"
311 "please fix it in %s:%u", value, filename, lineno);
312 add_rule_key(rule, &rule->subsystem, operation, "subsystem|class|bus");
314 add_rule_key(rule, &rule->subsystem, operation, value);
319 if (strcasecmp(key, "DRIVER") == 0) {
320 if (operation != KEY_OP_MATCH &&
321 operation != KEY_OP_NOMATCH) {
322 err(rules->udev, "invalid DRIVER operation\n");
325 add_rule_key(rule, &rule->driver, operation, value);
330 if (strncasecmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
331 attr = get_key_attribute(rules, key + sizeof("ATTR")-1);
333 err(rules->udev, "error parsing ATTR attribute\n");
336 if (add_rule_key_pair(rules, rule, &rule->attr, operation, attr, value) != 0)
342 if (strcasecmp(key, "KERNELS") == 0 ||
343 strcasecmp(key, "ID") == 0) {
344 if (operation != KEY_OP_MATCH &&
345 operation != KEY_OP_NOMATCH) {
346 err(rules->udev, "invalid KERNELS operation\n");
349 add_rule_key(rule, &rule->kernels, operation, value);
354 if (strcasecmp(key, "SUBSYSTEMS") == 0 ||
355 strcasecmp(key, "BUS") == 0) {
356 if (operation != KEY_OP_MATCH &&
357 operation != KEY_OP_NOMATCH) {
358 err(rules->udev, "invalid SUBSYSTEMS operation\n");
361 add_rule_key(rule, &rule->subsystems, operation, value);
366 if (strcasecmp(key, "DRIVERS") == 0) {
367 if (operation != KEY_OP_MATCH &&
368 operation != KEY_OP_NOMATCH) {
369 err(rules->udev, "invalid DRIVERS operation\n");
372 add_rule_key(rule, &rule->drivers, operation, value);
377 if (strncasecmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 ||
378 strncasecmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
379 if (operation != KEY_OP_MATCH &&
380 operation != KEY_OP_NOMATCH) {
381 err(rules->udev, "invalid ATTRS operation\n");
384 attr = get_key_attribute(rules, key + sizeof("ATTRS")-1);
386 err(rules->udev, "error parsing ATTRS attribute\n");
389 if (strncmp(attr, "device/", 7) == 0)
390 err(rules->udev, "the 'device' link is deprecated and will be removed from a future kernel, \n"
391 "please fix it in %s:%u", filename, lineno);
392 else if (strstr(attr, "../") != NULL)
393 err(rules->udev, "do not reference parent sysfs directories directly, that may break with a future kernel, \n"
394 "please fix it in %s:%u", filename, lineno);
395 if (add_rule_key_pair(rules, rule, &rule->attrs, operation, attr, value) != 0)
401 if (strncasecmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
402 attr = get_key_attribute(rules, key + sizeof("ENV")-1);
404 err(rules->udev, "error parsing ENV attribute\n");
407 if (strncmp(attr, "PHYSDEV", 7) == 0)
409 if (add_rule_key_pair(rules, rule, &rule->env, operation, attr, value) != 0)
415 if (strcasecmp(key, "PROGRAM") == 0) {
416 add_rule_key(rule, &rule->program, operation, value);
421 if (strcasecmp(key, "RESULT") == 0) {
422 if (operation != KEY_OP_MATCH &&
423 operation != KEY_OP_NOMATCH) {
424 err(rules->udev, "invalid RESULT operation\n");
427 add_rule_key(rule, &rule->result, operation, value);
432 if (strncasecmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
433 attr = get_key_attribute(rules, key + sizeof("IMPORT")-1);
434 if (attr != NULL && strstr(attr, "program")) {
435 dbg(rules->udev, "IMPORT will be executed\n");
436 rule->import_type = IMPORT_PROGRAM;
437 } else if (attr != NULL && strstr(attr, "file")) {
438 dbg(rules->udev, "IMPORT will be included as file\n");
439 rule->import_type = IMPORT_FILE;
440 } else if (attr != NULL && strstr(attr, "parent")) {
441 dbg(rules->udev, "IMPORT will include the parent values\n");
442 rule->import_type = IMPORT_PARENT;
444 /* figure it out if it is executable */
445 char file[PATH_SIZE];
449 strlcpy(file, value, sizeof(file));
450 pos = strchr(file, ' ');
454 /* allow programs in /lib/udev called without the path */
455 if (strchr(file, '/') == NULL) {
456 strlcpy(file, UDEV_PREFIX "/lib/udev/", sizeof(file));
457 strlcat(file, value, sizeof(file));
458 pos = strchr(file, ' ');
463 dbg(rules->udev, "IMPORT auto mode for '%s'\n", file);
464 if (!lstat(file, &statbuf) && (statbuf.st_mode & S_IXUSR)) {
465 dbg(rules->udev, "IMPORT is executable, will be executed (autotype)\n");
466 rule->import_type = IMPORT_PROGRAM;
468 dbg(rules->udev, "IMPORT is not executable, will be included as file (autotype)\n");
469 rule->import_type = IMPORT_FILE;
472 add_rule_key(rule, &rule->import, operation, value);
477 if (strncasecmp(key, "TEST", sizeof("TEST")-1) == 0) {
478 if (operation != KEY_OP_MATCH &&
479 operation != KEY_OP_NOMATCH) {
480 err(rules->udev, "invalid TEST operation\n");
483 attr = get_key_attribute(rules, key + sizeof("TEST")-1);
485 rule->test_mode_mask = strtol(attr, NULL, 8);
486 add_rule_key(rule, &rule->test, operation, value);
491 if (strncasecmp(key, "RUN", sizeof("RUN")-1) == 0) {
492 attr = get_key_attribute(rules, key + sizeof("RUN")-1);
494 if (strstr(attr, "ignore_error"))
495 rule->run_ignore_error = 1;
497 add_rule_key(rule, &rule->run, operation, value);
502 if (strcasecmp(key, "WAIT_FOR") == 0 || strcasecmp(key, "WAIT_FOR_SYSFS") == 0) {
503 add_rule_key(rule, &rule->wait_for, operation, value);
508 if (strcasecmp(key, "LABEL") == 0) {
509 add_rule_key(rule, &rule->label, operation, value);
514 if (strcasecmp(key, "GOTO") == 0) {
515 add_rule_key(rule, &rule->goto_label, operation, value);
520 if (strncasecmp(key, "NAME", sizeof("NAME")-1) == 0) {
521 attr = get_key_attribute(rules, key + sizeof("NAME")-1);
523 if (strstr(attr, "all_partitions") != NULL) {
524 dbg(rules->udev, "creation of partition nodes requested\n");
525 rule->partitions = DEFAULT_PARTITIONS_COUNT;
527 if (strstr(attr, "ignore_remove") != NULL) {
528 dbg(rules->udev, "remove event should be ignored\n");
529 rule->ignore_remove = 1;
532 if (value[0] == '\0')
533 dbg(rules->udev, "name empty, node creation supressed\n");
534 add_rule_key(rule, &rule->name, operation, value);
538 if (strcasecmp(key, "SYMLINK") == 0) {
539 if (operation == KEY_OP_MATCH ||
540 operation == KEY_OP_NOMATCH)
541 add_rule_key(rule, &rule->symlink_match, operation, value);
543 add_rule_key(rule, &rule->symlink, operation, value);
548 if (strcasecmp(key, "OWNER") == 0) {
550 if (rules->resolve_names && (!strchr(value, '$') && !strchr(value, '%'))) {
552 strtoul(value, &endptr, 10);
553 if (endptr[0] != '\0') {
555 uid_t uid = lookup_user(rules->udev, value);
556 dbg(rules->udev, "replacing username='%s' by id=%i\n", value, uid);
557 sprintf(owner, "%u", (unsigned int) uid);
558 add_rule_key(rule, &rule->owner, operation, owner);
563 add_rule_key(rule, &rule->owner, operation, value);
567 if (strcasecmp(key, "GROUP") == 0) {
569 if (rules->resolve_names && (!strchr(value, '$') && !strchr(value, '%'))) {
571 strtoul(value, &endptr, 10);
572 if (endptr[0] != '\0') {
574 gid_t gid = lookup_group(rules->udev, value);
575 dbg(rules->udev, "replacing groupname='%s' by id=%i\n", value, gid);
576 sprintf(group, "%u", (unsigned int) gid);
577 add_rule_key(rule, &rule->group, operation, group);
582 add_rule_key(rule, &rule->group, operation, value);
586 if (strcasecmp(key, "MODE") == 0) {
587 add_rule_key(rule, &rule->mode, operation, value);
592 if (strcasecmp(key, "OPTIONS") == 0) {
595 if (strstr(value, "last_rule") != NULL) {
596 dbg(rules->udev, "last rule to be applied\n");
599 if (strstr(value, "ignore_device") != NULL) {
600 dbg(rules->udev, "device should be ignored\n");
601 rule->ignore_device = 1;
603 if (strstr(value, "ignore_remove") != NULL) {
604 dbg(rules->udev, "remove event should be ignored\n");
605 rule->ignore_remove = 1;
607 pos = strstr(value, "link_priority=");
609 rule->link_priority = atoi(&pos[strlen("link_priority=")]);
610 dbg(rules->udev, "link priority=%i\n", rule->link_priority);
612 pos = strstr(value, "event_timeout=");
614 rule->event_timeout = atoi(&pos[strlen("event_timeout=")]);
615 dbg(rules->udev, "event timout=%i\n", rule->event_timeout);
617 pos = strstr(value, "string_escape=");
619 pos = &pos[strlen("string_escape=")];
620 if (strncmp(pos, "none", strlen("none")) == 0)
621 rule->string_escape = ESCAPE_NONE;
622 else if (strncmp(pos, "replace", strlen("replace")) == 0)
623 rule->string_escape = ESCAPE_REPLACE;
625 if (strstr(value, "all_partitions") != NULL) {
626 dbg(rules->udev, "creation of partition nodes requested\n");
627 rule->partitions = DEFAULT_PARTITIONS_COUNT;
633 err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
636 if (physdev && rule->wait_for.operation == KEY_OP_UNSET)
637 err(rules->udev, "PHYSDEV* values are deprecated and will be removed from a future kernel, \n"
638 "please fix it in %s:%u", filename, lineno);
640 /* skip line if not any valid key was found */
644 /* grow buffer and add rule */
645 rule_size = sizeof(struct udev_rule) + rule->bufsize;
646 padding = (sizeof(size_t) - rule_size % sizeof(size_t)) % sizeof(size_t);
647 dbg(rules->udev, "add %zi padding bytes\n", padding);
648 rule_size += padding;
649 rule->bufsize += padding;
651 rules->buf = realloc(rules->buf, rules->bufsize + rule_size);
653 err(rules->udev, "realloc failed\n");
656 dbg(rules->udev, "adding rule to offset %zi\n", rules->bufsize);
657 memcpy(rules->buf + rules->bufsize, rule, rule_size);
658 rules->bufsize += rule_size;
663 err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
667 static int parse_file(struct udev_rules *rules, const char *filename)
669 char line[LINE_SIZE];
678 if (file_map(filename, &buf, &bufsize) != 0) {
679 err(rules->udev, "can't open '%s' as rules file: %s\n", filename, strerror(errno));
682 info(rules->udev, "reading '%s' as rules file\n", filename);
684 /* loop through the whole file */
687 while (cur < bufsize) {
690 count = buf_get_line(buf, bufsize, cur);
695 /* eat the whitespace */
696 while ((count > 0) && isspace(bufline[0])) {
703 /* see if this is a comment */
704 if (bufline[0] == COMMENT_CHARACTER)
707 if (count >= sizeof(line)) {
708 err(rules->udev, "line too long, rule skipped '%s:%u'\n", filename, lineno);
712 /* skip backslash and newline from multiline rules */
713 for (i = j = 0; i < count; i++) {
714 if (bufline[i] == '\\' && bufline[i+1] == '\n')
717 line[j++] = bufline[i];
721 dbg(rules->udev, "read '%s'\n", line);
722 add_to_rules(rules, line, filename, lineno);
725 file_unmap(buf, bufsize);
729 int udev_rules_init(struct udev *udev, struct udev_rules *rules, int resolve_names)
732 char filename[PATH_MAX];
733 LIST_HEAD(name_list);
734 LIST_HEAD(sort_list);
735 struct name_entry *name_loop, *name_tmp;
736 struct name_entry *sort_loop, *sort_tmp;
739 memset(rules, 0x00, sizeof(struct udev_rules));
741 rules->resolve_names = resolve_names;
743 if (udev_get_rules_path(udev) != NULL) {
744 /* custom rules location for testing */
745 add_matching_files(udev, &name_list, udev_get_rules_path(udev), ".rules");
747 /* read user/custom rules */
748 add_matching_files(udev, &name_list, SYSCONFDIR "/udev/rules.d", ".rules");
750 /* read dynamic/temporary rules */
751 strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
752 strlcat(filename, "/.udev/rules.d", sizeof(filename));
753 if (stat(filename, &statbuf) != 0) {
754 create_path(udev, filename);
755 selinux_setfscreatecon(udev, filename, NULL, S_IFDIR|0755);
756 mkdir(filename, 0755);
757 selinux_resetfscreatecon(udev);
759 add_matching_files(udev, &sort_list, filename, ".rules");
761 /* read default rules */
762 add_matching_files(udev, &sort_list, UDEV_PREFIX "/lib/udev/rules.d", ".rules");
764 /* sort all rules files by basename into list of files */
765 list_for_each_entry_safe(sort_loop, sort_tmp, &sort_list, node) {
766 const char *sort_base = strrchr(sort_loop->name, '/');
768 if (sort_base == NULL)
771 list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) {
772 const char *name_base = strrchr(name_loop->name, '/');
774 if (name_base == NULL)
777 if (strcmp(name_base, sort_base) == 0) {
778 info(udev, "rule file '%s' already added, ignoring '%s'\n",
779 name_loop->name, sort_loop->name);
780 list_del(&sort_loop->node);
786 if (strcmp(name_base, sort_base) > 0)
789 if (sort_loop != NULL)
790 list_move_tail(&sort_loop->node, &name_loop->node);
794 /* parse list of files */
795 list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) {
796 if (stat(name_loop->name, &statbuf) == 0) {
798 parse_file(rules, name_loop->name);
800 dbg(udev, "empty rules file '%s'\n", name_loop->name);
802 err(udev, "could not read '%s': %s\n", name_loop->name, strerror(errno));
803 list_del(&name_loop->node);
810 void udev_rules_cleanup(struct udev_rules *rules)