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 8694b917a2cc98d954249810e232aadc53c879b1..32e057b1cb9c12a9c52c8384d2cccf440e90b3cd 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 52e0712d350411c7bd003028e294c70820a06da8..c416128b6284e4c720b3876d61b6456955316edb 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 2bf81075439d81021d355f68f689055c46d08805..cb628398024c209d6832b19690b930ba4a69c8e3 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 89925a35e42862c6f111ba281cf78f0e5ece4409..36bf97177db4172be9f648f18d1c36195a0a6d5e 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 64a7ba9caae0929356584acf1217f897fc43078e..c35b287881a060633f65e530abdf9390c0a48f69 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 b3e604fb98f99a6313d9bb35382934ede538a918..3e372dd9480402e18b7cae12e72afb9b343cb6fa 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;
+}