allow rules to be compiled to one binary file

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>
This commit is contained in:
Kay Sievers 2005-06-24 18:05:32 +02:00
parent c9b8dbfb65
commit 6bf0ffe8fd
15 changed files with 233 additions and 23 deletions

View file

@ -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 \

0
test/devd_test Normal file → Executable file
View file

0
test/net_test Normal file → Executable file
View file

0
test/replace_test Normal file → Executable file
View file

0
test/show_all_devices.sh Normal file → Executable file
View file

0
test/test.all Normal file → Executable file
View file

0
test/test.block Normal file → Executable file
View file

0
test/test.tty Normal file → Executable file
View file

0
test/testd.block Normal file → Executable file
View file

View 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;

View 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 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);
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);
#endif

View file

@ -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);
}
}

View 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);
}

View 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);

127
udevrulescompile.c Normal file
View file

@ -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;
}