chiark / gitweb /
allow rules to be compiled to one binary file
authorKay Sievers <kay.sievers@suse.de>
Fri, 24 Jun 2005 16:05:32 +0000 (18:05 +0200)
committerKay Sievers <kay.sievers@suse.de>
Fri, 24 Jun 2005 16:05:32 +0000 (18:05 +0200)
All the rule files can be compiled into a single file,
which can be mapped into the udev process to avoid parsing
the rules with every event.

Signed-off-by: Kay Sievers <kay.sievers@suse.de>
15 files changed:
Makefile
test/devd_test [changed mode: 0644->0755]
test/net_test [changed mode: 0644->0755]
test/replace_test [changed mode: 0644->0755]
test/show_all_devices.sh [changed mode: 0644->0755]
test/test.all [changed mode: 0644->0755]
test/test.block [changed mode: 0644->0755]
test/test.tty [changed mode: 0644->0755]
test/testd.block [changed mode: 0644->0755]
udev_rules.c
udev_rules.h
udev_rules_parse.c
udev_utils.c
udev_utils.h
udevrulescompile.c [new file with mode: 0644]

index 8694b91..32e057b 100644 (file)
--- 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 \
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 52e0712..c416128 100644 (file)
@@ -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;
 
index 2bf8107..cb62839 100644 (file)
@@ -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
index 89925a3..36bf971 100644 (file)
 #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);
+               }
 }
-
index 64a7ba9..c35b287 100644 (file)
@@ -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);
 }
index b3e604f..3e372dd 100644 (file)
@@ -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 (file)
index 0000000..ff9dd79
--- /dev/null
@@ -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;
+}