summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile11
-rwxr-xr-x[-rw-r--r--]test/devd_test0
-rwxr-xr-x[-rw-r--r--]test/net_test0
-rwxr-xr-x[-rw-r--r--]test/replace_test0
-rwxr-xr-x[-rw-r--r--]test/show_all_devices.sh0
-rwxr-xr-x[-rw-r--r--]test/test.all0
-rwxr-xr-x[-rw-r--r--]test/test.block0
-rwxr-xr-x[-rw-r--r--]test/test.tty0
-rwxr-xr-x[-rw-r--r--]test/testd.block0
-rw-r--r--udev_rules.c15
-rw-r--r--udev_rules.h8
-rw-r--r--udev_rules_parse.c89
-rw-r--r--udev_utils.c2
-rw-r--r--udev_utils.h2
-rw-r--r--udevrulescompile.c127
15 files changed, 232 insertions, 22 deletions
diff --git a/Makefile b/Makefile
index 8694b917a2..32e057b1cb 100644
--- a/Makefile
+++ b/Makefile
@@ -44,6 +44,7 @@ V=false
ROOT = udev
DAEMON = udevd
SENDER = udevsend
+COMPILE = udevrulescompile
INITSENDER = udevinitsend
RECORDER = udeveventrecorder
CONTROL = udevcontrol
@@ -202,7 +203,8 @@ endif
# config files automatically generated
GEN_CONFIGS = $(LOCAL_CFG_DIR)/udev.conf
-all: $(ROOT) $(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(DAEMON) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC)
+all: $(ROOT) $(SENDER) $(COMPILE) $(INITSENDER) $(RECORDER) $(CONTROL) \
+ $(DAEMON) $(COMPILE) $(INFO) $(TESTER) $(STARTER) $(GEN_CONFIGS) $(KLCC)
@extras="$(EXTRAS)" ; for target in $$extras ; do \
echo $$target ; \
$(MAKE) prefix=$(prefix) \
@@ -268,6 +270,7 @@ $(TESTER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(INFO).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(DAEMON).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(SENDER).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
+$(COMPILE).o: $(HEADERS) $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(INITSENDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(RECORDER).o: $(GEN_HEADERS) $(HOST_PROGS) $(KLCC)
$(CONTROL).o: $(HEADERS) $( $(HEADERS)GEN_HEADERS) $(HOST_PROGS) $(KLCC)
@@ -293,6 +296,10 @@ $(SENDER): $(KLCC) $(SENDER).o $(OBJS) udevd.h
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(SENDER).o $(OBJS) $(LIB_OBJS)
$(QUIET) $(STRIPCMD) $@
+$(COMPILE): $(KLCC) $(COMPILE).o $(OBJS)
+ $(QUIET) $(LD) $(LDFLAGS) -o $@ $(COMPILE).o $(OBJS) $(LIB_OBJS)
+ $(QUIET) $(STRIPCMD) $@
+
$(INITSENDER): $(KLCC) $(INITSENDER).o $(OBJS) udevd.h
$(QUIET) $(LD) $(LDFLAGS) -o $@ $(INITSENDER).o $(OBJS) $(LIB_OBJS)
$(QUIET) $(STRIPCMD) $@
@@ -316,7 +323,7 @@ clean:
-find . \( -not -type d \) -and \( -name '*~' -o -name '*.[oas]' \) -type f -print \
| xargs rm -f
-rm -f core $(ROOT) $(GEN_HEADERS) $(GEN_CONFIGS) $(GEN_MANPAGES) $(INFO) $(DAEMON) \
- $(SENDER) $(INITSENDER) $(RECORDER) $(CONTROL) $(TESTER) $(STARTER)
+ $(SENDER) $(COMPILE) $(INITSENDER) $(RECORDER) $(CONTROL) $(TESTER) $(STARTER)
-rm -f ccdv
$(MAKE) -C klibc SUBDIRS=klibc clean
@extras="$(EXTRAS)" ; for target in $$extras ; do \
diff --git a/test/devd_test b/test/devd_test
index 534e787f24..534e787f24 100644..100755
--- a/test/devd_test
+++ b/test/devd_test
diff --git a/test/net_test b/test/net_test
index 9daf8da082..9daf8da082 100644..100755
--- a/test/net_test
+++ b/test/net_test
diff --git a/test/replace_test b/test/replace_test
index 6e01f28ed5..6e01f28ed5 100644..100755
--- a/test/replace_test
+++ b/test/replace_test
diff --git a/test/show_all_devices.sh b/test/show_all_devices.sh
index 921b8e6163..921b8e6163 100644..100755
--- a/test/show_all_devices.sh
+++ b/test/show_all_devices.sh
diff --git a/test/test.all b/test/test.all
index 527569bd43..527569bd43 100644..100755
--- a/test/test.all
+++ b/test/test.all
diff --git a/test/test.block b/test/test.block
index 294c47c0be..294c47c0be 100644..100755
--- a/test/test.block
+++ b/test/test.block
diff --git a/test/test.tty b/test/test.tty
index b89ad5a6d8..b89ad5a6d8 100644..100755
--- a/test/test.tty
+++ b/test/test.tty
diff --git a/test/testd.block b/test/testd.block
index ca9ac8c1ac..ca9ac8c1ac 100644..100755
--- a/test/testd.block
+++ b/test/testd.block
diff --git a/udev_rules.c b/udev_rules.c
index 52e0712d35..c416128b62 100644
--- a/udev_rules.c
+++ b/udev_rules.c
@@ -846,7 +846,12 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
dbg("udev->kernel_name='%s'", udev->kernel_name);
/* look for a matching rule to apply */
- list_for_each_entry(rule, &udev_rule_list, node) {
+ udev_rules_iter_init();
+ while (1) {
+ rule = udev_rules_iter_next();
+ if (rule == NULL)
+ break;
+
if (udev->name_set && rule->name_operation != KEY_OP_UNSET) {
dbg("node name already set, rule ignored");
continue;
@@ -1000,9 +1005,13 @@ int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device)
struct udev_rule *rule;
/* look for a matching rule to apply */
- list_for_each_entry(rule, &udev_rule_list, node) {
- dbg("process rule");
+ udev_rules_iter_init();
+ while (1) {
+ rule = udev_rules_iter_next();
+ if (rule == NULL)
+ break;
+ dbg("process rule");
if (rule->run_operation == KEY_OP_UNSET)
continue;
diff --git a/udev_rules.h b/udev_rules.h
index 2bf8107543..cb62839802 100644
--- a/udev_rules.h
+++ b/udev_rules.h
@@ -123,11 +123,13 @@ struct udev_rule {
int config_line;
};
-extern struct list_head udev_rule_list;
-
extern int udev_rules_init(void);
+extern void udev_rules_close(void);
+
+extern int udev_rules_iter_init(void);
+extern struct udev_rule *udev_rules_iter_next(void);
+
extern int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev);
extern int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device);
-extern void udev_rules_close(void);
#endif
diff --git a/udev_rules_parse.c b/udev_rules_parse.c
index 89925a35e4..36bf97177d 100644
--- a/udev_rules_parse.c
+++ b/udev_rules_parse.c
@@ -37,9 +37,45 @@
#include "logging.h"
#include "udev_rules.h"
-LIST_HEAD(udev_rule_list);
+/* rules parsed from .rules files*/
+static LIST_HEAD(rules_list);
+static struct list_head *rules_list_current;
-static int add_config_dev(struct udev_rule *rule)
+/* mapped compiled rules stored on disk */
+static struct udev_rule *rules_array = NULL;
+static size_t rules_array_current;
+static size_t rules_array_size = 0;
+
+static size_t rules_count = 0;
+
+int udev_rules_iter_init(void)
+{
+ rules_list_current = rules_list.next;
+ rules_array_current = 0;
+
+ return 0;
+}
+
+struct udev_rule *udev_rules_iter_next(void)
+{
+ static struct udev_rule *rule;
+
+ if (rules_array) {
+ if (rules_array_current >= rules_count)
+ return NULL;
+ rule = &rules_array[rules_array_current];
+ rules_array_current++;
+ } else {
+ dbg("head=%p current=%p next=%p", &rules_list, rules_list_current, rules_list_current->next);
+ if (rules_list_current == &rules_list)
+ return NULL;
+ rule = list_entry(rules_list_current, struct udev_rule, node);
+ rules_list_current = rules_list_current->next;
+ }
+ return rule;
+}
+
+static int add_rule_to_list(struct udev_rule *rule)
{
struct udev_rule *tmp_rule;
@@ -47,7 +83,7 @@ static int add_config_dev(struct udev_rule *rule)
if (tmp_rule == NULL)
return -ENOMEM;
memcpy(tmp_rule, rule, sizeof(struct udev_rule));
- list_add_tail(&tmp_rule->node, &udev_rule_list);
+ list_add_tail(&tmp_rule->node, &rules_list);
dbg("name='%s', symlink='%s', bus='%s', id='%s', "
"sysfs_file[0]='%s', sysfs_value[0]='%s', "
@@ -451,9 +487,9 @@ static int rules_parse(const char *filename)
rule.config_line = lineno;
strlcpy(rule.config_file, filename, sizeof(rule.config_file));
- retval = add_config_dev(&rule);
+ retval = add_rule_to_list(&rule);
if (retval) {
- dbg("add_config_dev returned with error %d", retval);
+ dbg("add_rule_to_list returned with error %d", retval);
continue;
error:
err("parse error %s, line %d:%d, rule skipped",
@@ -465,20 +501,47 @@ error:
return retval;
}
+static int rules_map(const char *filename)
+{
+ char *buf;
+ size_t size;
+
+ if (file_map(filename, &buf, &size))
+ return -1;
+ if (size == 0)
+ return -1;
+ rules_array = (struct udev_rule *) buf;
+ rules_array_size = size;
+ rules_count = size / sizeof(struct udev_rule);
+ dbg("found %zi compiled rules", rules_count);
+
+ return 0;
+}
+
int udev_rules_init(void)
{
+ char comp[PATH_SIZE];
struct stat stats;
int retval;
+ strlcpy(comp, udev_rules_filename, sizeof(comp));
+ strlcat(comp, ".compiled", sizeof(comp));
+ if (stat(comp, &stats) == 0) {
+ dbg("parse compiled rules '%s'", comp);
+ return rules_map(comp);
+ }
+
if (stat(udev_rules_filename, &stats) != 0)
return -1;
- if ((stats.st_mode & S_IFMT) != S_IFDIR)
+ if ((stats.st_mode & S_IFMT) != S_IFDIR) {
+ dbg("parse single rules file '%s'", udev_rules_filename);
retval = rules_parse(udev_rules_filename);
- else {
+ } else {
struct name_entry *name_loop, *name_tmp;
LIST_HEAD(name_list);
+ dbg("parse rules directory '%s'", udev_rules_filename);
retval = add_matching_files(&name_list, udev_rules_filename, RULEFILE_SUFFIX);
list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) {
@@ -495,9 +558,11 @@ void udev_rules_close(void)
struct udev_rule *rule;
struct udev_rule *temp_rule;
- list_for_each_entry_safe(rule, temp_rule, &udev_rule_list, node) {
- list_del(&rule->node);
- free(rule);
- }
+ if (rules_array)
+ file_unmap(rules_array, rules_array_size);
+ else
+ list_for_each_entry_safe(rule, temp_rule, &rules_list, node) {
+ list_del(&rule->node);
+ free(rule);
+ }
}
-
diff --git a/udev_utils.c b/udev_utils.c
index 64a7ba9caa..c35b287881 100644
--- a/udev_utils.c
+++ b/udev_utils.c
@@ -247,7 +247,7 @@ int file_map(const char *filename, char **buf, size_t *bufsize)
return 0;
}
-void file_unmap(char *buf, size_t bufsize)
+void file_unmap(void *buf, size_t bufsize)
{
munmap(buf, bufsize);
}
diff --git a/udev_utils.h b/udev_utils.h
index b3e604fb98..3e372dd948 100644
--- a/udev_utils.h
+++ b/udev_utils.h
@@ -39,7 +39,7 @@ extern int string_is_true(const char *str);
extern int parse_get_pair(char **orig_string, char **left, char **right);
extern int unlink_secure(const char *filename);
extern int file_map(const char *filename, char **buf, size_t *bufsize);
-extern void file_unmap(char *buf, size_t bufsize);
+extern void file_unmap(void *buf, size_t bufsize);
extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);
extern void remove_trailing_char(char *path, char c);
extern void replace_untrusted_chars(char *string);
diff --git a/udevrulescompile.c b/udevrulescompile.c
new file mode 100644
index 0000000000..ff9dd79fd4
--- /dev/null
+++ b/udevrulescompile.c
@@ -0,0 +1,127 @@
+/*
+ * udevrulescompile.c - store already parsed config on disk
+ *
+ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "udev_libc_wrapper.h"
+#include "udev_sysfs.h"
+#include "udev.h"
+#include "udev_version.h"
+#include "logging.h"
+#include "udev_rules.h"
+#include "udev_utils.h"
+#include "list.h"
+
+#ifdef USE_LOG
+void log_message(int priority, const char *format, ...)
+{
+ va_list args;
+
+ if (priority > udev_log_priority)
+ return;
+
+ va_start(args, format);
+ vsyslog(priority, format, args);
+ va_end(args);
+}
+#endif
+
+int main(int argc, char *argv[], char *envp[])
+{
+ struct udev_rule *rule;
+ FILE *f;
+ char comp[PATH_SIZE];
+ char comp_tmp[PATH_SIZE];
+ int retval = 0;
+
+ logging_init("udevrulescompile");
+ udev_init_config();
+ dbg("version %s", UDEV_VERSION);
+
+ strlcpy(comp, udev_rules_filename, sizeof(comp));
+ strlcat(comp, ".compiled", sizeof(comp));
+ strlcpy(comp_tmp, comp, sizeof(comp_tmp));
+ strlcat(comp_tmp, ".tmp", sizeof(comp_tmp));
+
+ /* remove old version, otherwise we would read it
+ * instead of the real rules */
+ unlink(comp);
+ unlink(comp_tmp);
+
+ udev_rules_init();
+
+ f = fopen(comp_tmp, "w");
+ if (f == NULL) {
+ err("unable to create db file '%s'", comp_tmp);
+ unlink(comp_tmp);
+ retval = 1;
+ goto exit;
+ }
+ dbg("storing compiled rules in '%s'", comp_tmp);
+
+ udev_rules_iter_init();
+ while (1) {
+ char *endptr;
+ unsigned long id;
+
+ rule = udev_rules_iter_next();
+ if (rule == NULL)
+ break;
+
+ id = strtoul(rule->owner, &endptr, 10);
+ if (endptr[0] != '\0') {
+ uid_t uid;
+
+ uid = lookup_user(rule->owner);
+ dbg("replacing username='%s' by id=%i", rule->owner, uid);
+ sprintf(rule->owner, "%li", uid);
+ }
+
+ id = strtoul(rule->group, &endptr, 10);
+ if (endptr[0] != '\0') {
+ gid_t gid;
+
+ gid = lookup_group(rule->group);
+ dbg("replacing groupname='%s' by id=%i", rule->group, gid);
+ sprintf(rule->group, "%li", gid);
+ }
+
+ dbg("kernel='%s' name='%s'", rule->kernel, rule->name);
+ fwrite(rule, sizeof(struct udev_rule), 1, f);
+ }
+
+ fclose(f);
+ dbg("activating compiled rules in '%s'", comp);
+ if (rename(comp_tmp, comp) != 0) {
+ err("unable to write file");
+ unlink(comp);
+ unlink(comp_tmp);
+ retval = 2;
+ }
+
+exit:
+ logging_close();
+ return retval;
+}