hal: Branch 'master' - 2 commits
David Zeuthen
david at kemper.freedesktop.org
Wed Jan 10 21:49:11 PST 2007
configure.in | 2
hald/Makefile.am | 24 +
hald/create_cache.c | 666 +++++++++++++++++++++++++++++++++++++++++++++++++
hald/debug-hald.sh | 1
hald/device_info.c | 678 +++++---------------------------------------------
hald/device_info.h | 1
hald/hald.c | 12
hald/hald_runner.c | 18 -
hald/mmap_cache.c | 239 +++++++++++++++++
hald/mmap_cache.h | 37 ++
hald/rule.h | 111 ++++++++
hald/run-hald.sh | 1
hald/valgrind-hald.sh | 1
13 files changed, 1176 insertions(+), 615 deletions(-)
New commits:
diff-tree de7ada8fd2a5675554d6723b9145afa4e719e8a0 (from 285b20f453bd4ce5f963a9818711c7ffd38437d7)
Author: David Zeuthen <davidz at redhat.com>
Date: Thu Jan 11 00:48:57 2007 -0500
fix up a few things with the new fdi cache
- CACHE_FILE and HALD_CACHE_BIN shouldn't be set from configure.in
- instead of installing the helper in /sbin and caling it hald-cache
rather call it hald-generate-fdi-cache and install it in /usr/libexec
since only hald will call it
- make the runner capable of invoking programs when device==NULL
- make hald invoke the fdi cache generator using the runner; otherwise
./run-hald.sh and friends will not work if your home directory is
unreadable by the haldaemon user
- create /var/cache/hald in install-data-local. Also fixup the missing
use of $DESTDIR of /var/run/hald stuff
- s/cache_coherency_check()/di_cache_coherency_check()/
- wait for runner to be initialized before invoking di_cache_coherency_check()
- fix di_cache_coherency_check() so it respects $HAL_FDI_SOURCE_* and
also $HAL_FDI_CACHE_NAME
- remote the cache-test program for now as we now require the runner
- fix up ./run-hald.sh and friends to use a cache in .local-fdi thereby
not polluting the global cache
diff --git a/configure.in b/configure.in
index f7571f0..c479de3 100644
--- a/configure.in
+++ b/configure.in
@@ -450,12 +450,6 @@ fi
AC_SUBST(DBUS_SYS_DIR)
AC_DEFINE_UNQUOTED(DBUS_SYSTEMD_DIR, "$DBUS_SYS_DIR", [Where system.d dir for DBUS is])
-AC_SUBST(CACHE_FILE)
-AC_DEFINE_UNQUOTED(CACHE_FILE,"$LOCALSTATEDIR/cache/hald/fdi_cache", [Where FDI cache file is stored])
-
-AC_SUBST(HALD_CACHE_BIN)
-AC_DEFINE_UNQUOTED(HALD_CACHE_BIN,"$SBINDIR/hald-cache", [Cache generator binary])
-
#### Check our operating system (distro-tweaks required)
operating_system=unknown
if test -f /etc/redhat-release || test -f SYSCONFDIR/redhat-release ; then
diff --git a/hald/Makefile.am b/hald/Makefile.am
index e72d55d..4023762 100644
--- a/hald/Makefile.am
+++ b/hald/Makefile.am
@@ -30,19 +30,15 @@ INCLUDES = \
# TESTS = hald-test
-sbin_PROGRAMS = hald hald-cache
+sbin_PROGRAMS = hald
+libexec_PROGRAMS = hald-generate-fdi-cache
BUILT_SOURCES = \
hald_marshal.h \
hald_marshal.c
-noinst_PROGRAMS = hald-cache-test
-
-hald_cache_SOURCES = create_cache.c logger.h logger.c rule.h
-hald_cache_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
-
-hald_cache_test_SOURCES = cache_test.c logger.h logger.c rule.h mmap_cache.c mmap_cache.h
-hald_cache_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
+hald_generate_fdi_cache_SOURCES = create_cache.c logger.h logger.c rule.h
+hald_generate_fdi_cache_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
hald_SOURCES = \
hald_marshal.h hald_marshal.c \
@@ -91,11 +87,13 @@ hald_marshal.c: hald_marshal.list
install-data-local:
- -$(mkdir_p) $(HALD_SOCKET_DIR)
- -chown $(HAL_USER):$(HAL_GROUP) $(HALD_SOCKET_DIR)
- -chmod 0755 $(HALD_SOCKET_DIR)
- -$(mkdir_p) $(HALD_SOCKET_DIR)/hald-local
- -$(mkdir_p) $(HALD_SOCKET_DIR)/hald-runner
+ -$(mkdir_p) $(DESTDIR)$(HALD_SOCKET_DIR)
+ -chown $(HAL_USER):$(HAL_GROUP) $(DESTDIR)$(HALD_SOCKET_DIR)
+ -chmod 0755 $(DESTDIR)$(HALD_SOCKET_DIR)
+ -$(mkdir_p) $(DESTDIR)$(HALD_SOCKET_DIR)/hald-local
+ -$(mkdir_p) $(DESTDIR)$(HALD_SOCKET_DIR)/hald-runner
+ -$(mkdir_p) $(DESTDIR)$(localstatedir)/cache/hald
+ -chown $(HAL_USER):$(HAL_GROUP) $(DESTDIR)$(localstatedir)/cache/hald
clean-local:
rm -f *~
diff --git a/hald/cache_test.c b/hald/cache_test.c
deleted file mode 100644
index a5a499d..0000000
--- a/hald/cache_test.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/***************************************************************************
- * CVSID: $Id$
- *
- * cache_test.c : test FDI cache.
- *
- * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
- * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
- * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
- * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
- * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
- *
- * Licensed under the Academic Free License version 2.1
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- **************************************************************************/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <dirent.h>
-#include <errno.h>
-#include <expat.h>
-#include <glib.h>
-#include <config.h>
-
-#include "logger.h"
-#include "rule.h"
-#include "mmap_cache.h"
-
-void *rules_ptr = NULL;
-
-static void test_cache(u_int32_t offset, size_t size){
- u_int32_t m = offset;
- struct rule *r;
-
- while(m < offset + size){
- r = (struct rule *) RULES_PTR(m);
-
- HAL_INFO(("rule=%08lx, rule_size=%d, rtype=%d", m, r->rule_size, r->rtype));
- HAL_INFO((" jump_position=%08lx", r->jump_position));
- HAL_INFO((" key='%s', key_len=%d, key_offset=%08lx",
- r->key, r->key_len, m + offsetof(struct rule, key)));
- HAL_INFO((" value='%s', value_len=%d, value_offset=%08lx",
- (char*)rules_ptr + r->value_offset, r->value_len, r->value_offset));
-
- m += r->rule_size;
- }
-}
-
-int main(){
- struct cache_header *header;
-
- cache_coherency_check();
- di_rules_init();
- header = (struct cache_header*) RULES_PTR(0);
-
- test_cache(header->fdi_rules_preprobe, header->fdi_rules_information - header->fdi_rules_preprobe);
- test_cache(header->fdi_rules_information, header->fdi_rules_policy - header->fdi_rules_information);
- test_cache(header->fdi_rules_policy, header->all_rules_size - header->fdi_rules_policy);
- return 0;
-}
diff --git a/hald/create_cache.c b/hald/create_cache.c
index e4c2c30..4d016d1 100644
--- a/hald/create_cache.c
+++ b/hald/create_cache.c
@@ -513,7 +513,8 @@ di_rules_init (void)
char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
cachename = getenv ("HAL_FDI_CACHE_NAME");
- if(!cachename) cachename = CACHE_FILE;
+ if(cachename == NULL)
+ cachename = HALD_CACHE_FILE;
HAL_INFO (("Loading rules"));
if(haldc_force_recreate && !stat(cachename, &st)) {
diff --git a/hald/debug-hald.sh b/hald/debug-hald.sh
index bda8c94..379ff49 100755
--- a/hald/debug-hald.sh
+++ b/hald/debug-hald.sh
@@ -17,6 +17,7 @@ fi
export HAL_FDI_SOURCE_PREPROBE=.local-fdi/share/hal/fdi/preprobe
export HAL_FDI_SOURCE_INFORMATION=.local-fdi/share/hal/fdi/information
export HAL_FDI_SOURCE_POLICY=.local-fdi/share/hal/fdi/policy
+export HAL_FDI_CACHE_NAME=.local-fdi/hald-local-fdi-cache
echo ========================================
echo Just type \'run\' to start debugging hald
diff --git a/hald/hald.c b/hald/hald.c
index 8c7875b..4e4f1c6 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -505,8 +505,6 @@ main (int argc, char *argv[])
HAL_INFO ((PACKAGE_STRING));
- cache_coherency_check();
-
if (opt_become_daemon) {
int child_pid;
int dev_null_fd;
@@ -613,11 +611,14 @@ main (int argc, char *argv[])
drop_privileges(0);
}
+ hald_is_initialising = TRUE;
+
+ /* make sure our fdi rule cache is up to date */
+ di_cache_coherency_check();
+
/* initialize operating system specific parts */
osspec_init ();
- hald_is_initialising = TRUE;
-
/* Init FDI files */
di_rules_init();
diff --git a/hald/hald_runner.c b/hald/hald_runner.c
index 32abd9c..41fa987 100644
--- a/hald/hald_runner.c
+++ b/hald/hald_runner.c
@@ -397,14 +397,19 @@ add_first_part(DBusMessageIter *iter, Ha
DBusMessageIter array_iter;
const char *udi;
- udi = hal_device_get_udi(device);
+ if (device != NULL)
+ udi = hal_device_get_udi(device);
+ else
+ udi = "";
+
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &udi);
dbus_message_iter_open_container(iter,
DBUS_TYPE_ARRAY,
DBUS_TYPE_STRING_AS_STRING,
&array_iter);
- hal_device_property_foreach (device, add_property_to_msg, &array_iter);
+ if (device != NULL)
+ hal_device_property_foreach (device, add_property_to_msg, &array_iter);
add_basic_env(&array_iter, udi);
add_extra_env(&array_iter, extra_env);
dbus_message_iter_close_container(iter, &array_iter);
@@ -512,7 +517,8 @@ call_notify(DBusPendingCall *pending, vo
hb->cb(hb->d, exitt, return_code,
(gchar **)error->data, hb->data1, hb->data2);
- g_object_unref (hb->d);
+ if (hb->d != NULL)
+ g_object_unref (hb->d);
dbus_message_unref(m);
g_array_free(error, TRUE);
@@ -526,7 +532,8 @@ malformed:
HAL_ERROR (("Malformed or unexpected reply message"));
hb->cb(hb->d, HALD_RUN_FAILED, return_code, NULL, hb->data1, hb->data2);
- g_object_unref (hb->d);
+ if (hb->d != NULL)
+ g_object_unref (hb->d);
dbus_message_unref(m);
g_array_free(error, TRUE);
@@ -575,7 +582,8 @@ hald_runner_run_method(HalDevice *device
hd->data1 = data1;
hd->data2 = data2;
- g_object_ref (device);
+ if (device != NULL)
+ g_object_ref (device);
dbus_pending_call_set_notify(call, call_notify, hd, NULL);
dbus_message_unref(msg);
diff --git a/hald/mmap_cache.c b/hald/mmap_cache.c
index e43c6da..45e0ebe 100644
--- a/hald/mmap_cache.c
+++ b/hald/mmap_cache.c
@@ -43,6 +43,7 @@
#include "logger.h"
#include "rule.h"
#include "mmap_cache.h"
+#include "hald_runner.h"
extern void *rules_ptr;
@@ -53,7 +54,8 @@ void di_rules_init(void){
struct stat statbuf;
cachename = getenv ("HAL_FDI_CACHE_NAME");
- if(!cachename) cachename = CACHE_FILE;
+ if(cachename == NULL)
+ cachename = HALD_CACHE_FILE;
if((fd = open(cachename, O_RDONLY)) < 0)
DIE(("Unable to open cache %s\n", cachename));
@@ -78,83 +80,160 @@ void di_rules_init(void){
static void dir_mtime(const char * path, time_t * mt)
{
- struct dirent **namelist;
- struct stat st;
- int n;
- char cpath[PATH_MAX];
-
- if (!stat(path, &st)) {
- if(st.st_mtime > *mt)
- *mt = st.st_mtime;
-
- if(S_ISDIR(st.st_mode)) {
- n = scandir(path, &namelist, 0, alphasort);
- if (n < 0)
- return;
- else {
- while(n--) {
+ struct dirent **namelist;
+ struct stat st;
+ int n;
+ char cpath[PATH_MAX];
+
+ if (!stat(path, &st)) {
+ if(st.st_mtime > *mt)
+ *mt = st.st_mtime;
+
+ if(S_ISDIR(st.st_mode)) {
+ n = scandir(path, &namelist, 0, alphasort);
+ if (n < 0)
+ return;
+ else {
+ while(n--) {
#ifdef HAVE_SNPRINTF
- snprintf(cpath, PATH_MAX, "%s/%s", path, namelist[n]->d_name);
+ snprintf(cpath, PATH_MAX, "%s/%s", path, namelist[n]->d_name);
#else
- sprintf(cpath, "%s/%s", path, namelist[n]->d_name);
+ sprintf(cpath, "%s/%s", path, namelist[n]->d_name);
#endif
- if(namelist[n]->d_name[0] != '.')
- dir_mtime(cpath, mt);
+ if(namelist[n]->d_name[0] != '.')
+ dir_mtime(cpath, mt);
+
+ free(namelist[n]);
+ }
+ free(namelist);
+ }
+ }
+ }
+}
+
+
+static gboolean regen_cache_done;
+static gint regen_cache_success;
- free(namelist[n]);
- }
- free(namelist);
- }
+static void
+regen_cache_cb (HalDevice *d,
+ guint32 exit_type,
+ gint return_code,
+ gchar **error,
+ gpointer data1,
+ gpointer data2)
+{
+ HAL_INFO (("In regen_cache_cb exit_type=%d, return_code=%d", exit_type, return_code));
+
+ if (exit_type != HALD_RUN_SUCCESS || return_code != 0) {
+ regen_cache_success = FALSE;
+ } else {
+ regen_cache_success = TRUE;
}
- }
+
+ regen_cache_done = TRUE;
}
-static void regen_cache(void)
+
+static void
+regen_cache (void)
{
- int ret;
- struct stat st;
- char cmd [PATH_MAX + 9];
- char * c;
-
- if((c = getenv("HALD_CACHE_BIN")) == NULL) {
- c = HALD_CACHE_BIN;
- }
-#ifdef HAVE_SNPRINTF
- snprintf(cmd, PATH_MAX + 8, "%s --force", c);
-#else
- sprintf(cmd, "%s --force", c);
-#endif
+ int n, m;
+ char *extra_env[5] = {NULL, NULL, NULL, NULL, NULL};
+ char *env_names[5] = {"HAL_FDI_SOURCE_PREPROBE",
+ "HAL_FDI_SOURCE_INFORMATION",
+ "HAL_FDI_SOURCE_POLICY",
+ "HAL_FDI_CACHE_NAME",
+ NULL};
+
+ HAL_INFO (("Regenerating fdi cache.."));
+
+ /* pass these variables to the helper */
+ for (n = 0, m = 0; env_names[n] != NULL; n++) {
+ char *name;
+ char *val;
+
+ name = env_names[n];
+ val = getenv(name);
+ if (val != NULL) {
+ extra_env [m++] = g_strdup_printf ("%s=%s", name, val);
+ }
+ }
+
+ regen_cache_done = FALSE;
+
+ hald_runner_run (NULL,
+ "hald-generate-fdi-cache --force",
+ extra_env,
+ 10000,
+ regen_cache_cb,
+ NULL,
+ NULL);
- if(!stat(c, &st) && (ret = system(cmd)) !=- 1) {
+ for (n = 0; extra_env[n] != NULL; n++) {
+ g_free (extra_env[n]);
+ }
+
+ while (!regen_cache_done) {
+ g_main_context_iteration (NULL, TRUE);
+ }
- if(WTERMSIG(ret) == SIGQUIT || WTERMSIG(ret) == SIGINT)
- DIE(("Cache creation was interrupted"));
+ if (!regen_cache_success) {
+ DIE (("fdi cache regeneration failed!"));
+ }
- if(WEXITSTATUS(ret) == 0)
- HAL_INFO(("Subprocess terminated normally, cache generated."));
- }
- else {
- HAL_INFO(("Unable to generate cache"));
- }
+ HAL_INFO (("fdi cache generation done"));
}
-void cache_coherency_check(void)
+
+void
+di_cache_coherency_check (void)
{
- time_t mt;
- struct stat st;
- dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/preprobe", &mt);
- dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", &mt);
- dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/information", &mt);
- dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/information", &mt);
- dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/policy", &mt);
- dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/policy", &mt);
- if(!stat(CACHE_FILE, &st)) {
- if(st.st_mtime < mt) {
- HAL_INFO(("Cache needs update"));
- regen_cache();
+ char *hal_fdi_source_preprobe;
+ char *hal_fdi_source_information;
+ char *hal_fdi_source_policy;
+ char *cachename;
+ time_t mt;
+ struct stat st;
+
+ mt = 0;
+
+ hal_fdi_source_preprobe = getenv ("HAL_FDI_SOURCE_PREPROBE");
+ hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
+ hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
+
+ if (hal_fdi_source_preprobe != NULL) {
+ dir_mtime (hal_fdi_source_preprobe, &mt);
+ } else {
+ dir_mtime (PACKAGE_DATA_DIR "/hal/fdi/preprobe", &mt);
+ dir_mtime (PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", &mt);
+ }
+
+ if (hal_fdi_source_information != NULL) {
+ dir_mtime (hal_fdi_source_information, &mt);
+ } else {
+ dir_mtime (PACKAGE_DATA_DIR "/hal/fdi/information", &mt);
+ dir_mtime (PACKAGE_SYSCONF_DIR "/hal/fdi/information", &mt);
+ }
+
+ if (hal_fdi_source_policy != NULL) {
+ dir_mtime (hal_fdi_source_policy, &mt);
+ } else {
+ dir_mtime (PACKAGE_DATA_DIR "/hal/fdi/policy", &mt);
+ dir_mtime (PACKAGE_SYSCONF_DIR "/hal/fdi/policy", &mt);
}
- }
- else
- regen_cache();
- HAL_INFO(("cache mtime is %d",mt));
+ cachename = getenv ("HAL_FDI_CACHE_NAME");
+ if(cachename == NULL)
+ cachename = HALD_CACHE_FILE;
+
+ if(stat (cachename, &st) == 0) {
+ if(st.st_mtime < mt) {
+ HAL_INFO(("Cache needs update"));
+ regen_cache();
+ }
+ } else {
+ regen_cache();
+ }
+
+ HAL_INFO(("cache mtime is %d",mt));
}
diff --git a/hald/mmap_cache.h b/hald/mmap_cache.h
index 5c136d5..bfafeb4 100644
--- a/hald/mmap_cache.h
+++ b/hald/mmap_cache.h
@@ -31,7 +31,7 @@
#ifndef __MMAP_CACHE_H__
void di_rules_init(void);
-void cache_coherency_check(void);
+void di_cache_coherency_check(void);
#define RULES_PTR(x) ((void *)((unsigned char *) rules_ptr + x))
#endif
diff --git a/hald/rule.h b/hald/rule.h
index 9c726d3..cb82e62 100644
--- a/hald/rule.h
+++ b/hald/rule.h
@@ -106,4 +106,6 @@ struct cache_header {
#define HAL_MAX_INDENT_DEPTH 64
+#define HALD_CACHE_FILE PACKAGE_LOCALSTATEDIR "/cache/hald/fdi-cache"
+
#endif
diff --git a/hald/run-hald.sh b/hald/run-hald.sh
index ed32d1e..88d55e1 100755
--- a/hald/run-hald.sh
+++ b/hald/run-hald.sh
@@ -25,6 +25,7 @@ fi
export HAL_FDI_SOURCE_PREPROBE=.local-fdi/share/hal/fdi/preprobe
export HAL_FDI_SOURCE_INFORMATION=.local-fdi/share/hal/fdi/information
export HAL_FDI_SOURCE_POLICY=.local-fdi/share/hal/fdi/policy
+export HAL_FDI_CACHE_NAME=.local-fdi/hald-local-fdi-cache
./hald --daemon=no --verbose=yes $@
#./hald --daemon=no
diff --git a/hald/valgrind-hald.sh b/hald/valgrind-hald.sh
index eab6e5c..28bd581 100755
--- a/hald/valgrind-hald.sh
+++ b/hald/valgrind-hald.sh
@@ -17,6 +17,7 @@ fi
export HAL_FDI_SOURCE_PREPROBE=.local-fdi/share/hal/fdi/preprobe
export HAL_FDI_SOURCE_INFORMATION=.local-fdi/share/hal/fdi/information
export HAL_FDI_SOURCE_POLICY=.local-fdi/share/hal/fdi/policy
+export HAL_FDI_CACHE_NAME=.local-fdi/hald-local-fdi-cache
#valgrind --num-callers=20 --show-reachable=yes --leak-check=yes --tool=memcheck ./hald --daemon=no --verbose=yes $@
valgrind --show-reachable=yes --tool=memcheck --leak-check=full ./hald --daemon=no --verbose=yes $@
diff-tree 285b20f453bd4ce5f963a9818711c7ffd38437d7 (from cdca0a7dc663d5e174e811b2c17afd7491537aa2)
Author: Sergey Lapin <slapinid at gmail.com>
Date: Wed Jan 10 22:55:09 2007 -0500
move fdi file parsing into a separate process
David Zeuthen wrote:
> On Tue, 2007-01-09 at 16:20 +0300, Sergey Lapin wrote:
>> Hi!
>>
>> Attached is a patch which provides these improvements:
>>
>> - Separates XML parsing from main running process thus reducing memory
>> fragmentation and consumption.
>> - maintains binary cache which is mmapped for reading thus not using
>> heap for that, so it uses mapped memory which is freed on demand which
>> is good for small-memory embedded devices.
>> - makes hald smaller due to fact that bunch of rarely used code is out
>> in separate process.
It is updated version of patch:
- Fixed code style issues and cut-paste comment errors
- Created trivial cache coherency check (mtime)
- moved test binary to noinst
- made proper command line options for hald-cache
- proper logger setup with hald-cache
diff --git a/configure.in b/configure.in
index 54639de..f7571f0 100644
--- a/configure.in
+++ b/configure.in
@@ -388,6 +388,7 @@ fi
AC_CHECK_FUNCS(getgrouplist)
AC_CHECK_FUNCS(asprintf)
AC_CHECK_FUNCS(mallopt)
+AC_CHECK_FUNCS(strndup)
# DocBook Documentation
@@ -449,6 +450,11 @@ fi
AC_SUBST(DBUS_SYS_DIR)
AC_DEFINE_UNQUOTED(DBUS_SYSTEMD_DIR, "$DBUS_SYS_DIR", [Where system.d dir for DBUS is])
+AC_SUBST(CACHE_FILE)
+AC_DEFINE_UNQUOTED(CACHE_FILE,"$LOCALSTATEDIR/cache/hald/fdi_cache", [Where FDI cache file is stored])
+
+AC_SUBST(HALD_CACHE_BIN)
+AC_DEFINE_UNQUOTED(HALD_CACHE_BIN,"$SBINDIR/hald-cache", [Cache generator binary])
#### Check our operating system (distro-tweaks required)
operating_system=unknown
diff --git a/hald/Makefile.am b/hald/Makefile.am
index e1daa08..e72d55d 100644
--- a/hald/Makefile.am
+++ b/hald/Makefile.am
@@ -30,12 +30,20 @@ INCLUDES = \
# TESTS = hald-test
-sbin_PROGRAMS = hald
+sbin_PROGRAMS = hald hald-cache
BUILT_SOURCES = \
hald_marshal.h \
hald_marshal.c
+noinst_PROGRAMS = hald-cache-test
+
+hald_cache_SOURCES = create_cache.c logger.h logger.c rule.h
+hald_cache_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
+
+hald_cache_test_SOURCES = cache_test.c logger.h logger.c rule.h mmap_cache.c mmap_cache.h
+hald_cache_test_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
+
hald_SOURCES = \
hald_marshal.h hald_marshal.c \
util.h util.c \
@@ -49,9 +57,13 @@ hald_SOURCES =
hald_dbus.h hald_dbus.c \
logger.h logger.c \
osspec.h \
- ids.h ids.c
+ ids.h ids.c \
+ rule.h mmap_cache.c \
+ mmap_cache.h
+
+
-hald_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
+hald_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
#### Init scripts fun
SCRIPT_IN_FILES=haldaemon.in
diff --git a/hald/cache_test.c b/hald/cache_test.c
new file mode 100644
index 0000000..a5a499d
--- /dev/null
+++ b/hald/cache_test.c
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * cache_test.c : test FDI cache.
+ *
+ * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <dirent.h>
+#include <errno.h>
+#include <expat.h>
+#include <glib.h>
+#include <config.h>
+
+#include "logger.h"
+#include "rule.h"
+#include "mmap_cache.h"
+
+void *rules_ptr = NULL;
+
+static void test_cache(u_int32_t offset, size_t size){
+ u_int32_t m = offset;
+ struct rule *r;
+
+ while(m < offset + size){
+ r = (struct rule *) RULES_PTR(m);
+
+ HAL_INFO(("rule=%08lx, rule_size=%d, rtype=%d", m, r->rule_size, r->rtype));
+ HAL_INFO((" jump_position=%08lx", r->jump_position));
+ HAL_INFO((" key='%s', key_len=%d, key_offset=%08lx",
+ r->key, r->key_len, m + offsetof(struct rule, key)));
+ HAL_INFO((" value='%s', value_len=%d, value_offset=%08lx",
+ (char*)rules_ptr + r->value_offset, r->value_len, r->value_offset));
+
+ m += r->rule_size;
+ }
+}
+
+int main(){
+ struct cache_header *header;
+
+ cache_coherency_check();
+ di_rules_init();
+ header = (struct cache_header*) RULES_PTR(0);
+
+ test_cache(header->fdi_rules_preprobe, header->fdi_rules_information - header->fdi_rules_preprobe);
+ test_cache(header->fdi_rules_information, header->fdi_rules_policy - header->fdi_rules_information);
+ test_cache(header->fdi_rules_policy, header->all_rules_size - header->fdi_rules_policy);
+ return 0;
+}
diff --git a/hald/create_cache.c b/hald/create_cache.c
new file mode 100644
index 0000000..e4c2c30
--- /dev/null
+++ b/hald/create_cache.c
@@ -0,0 +1,665 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * create_cache.c : create FDI cache.
+ *
+ * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <malloc.h>
+#include <errno.h>
+#include <string.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <expat.h>
+#include <glib.h>
+#include <config.h>
+
+#include "logger.h"
+#include "rule.h"
+
+/* ctx of the current fdi file used for parsing */
+struct fdi_context {
+ int depth;
+ u_int32_t match_at_depth[HAL_MAX_INDENT_DEPTH];
+ struct rule rule;
+ off_t position;
+ int cache_fd;
+};
+
+/* modified alphasort to count downwards */
+static int
+#ifdef __GLIBC__
+_alphasort(const void *a, const void *b)
+#else
+_alphasort(const struct dirent **a, const struct dirent **b)
+#endif
+{
+ return -alphasort (a, b);
+}
+
+
+static enum
+rule_type get_rule_type (const char *str)
+{
+ if (strcmp (str, "match") == 0)
+ return RULE_MATCH;
+ if (strcmp (str, "merge") == 0)
+ return RULE_MERGE;
+ if (strcmp (str, "append") == 0)
+ return RULE_APPEND;
+ if (strcmp (str, "prepend") == 0)
+ return RULE_PREPEND;
+ if (strcmp (str, "remove") == 0)
+ return RULE_REMOVE;
+ if (strcmp (str, "clear") == 0)
+ return RULE_CLEAR;
+ if (strcmp (str, "spawn") == 0)
+ return RULE_SPAWN;
+ return RULE_UNKNOWN;
+}
+
+static enum
+match_type get_match_type(const char *str)
+{
+ if (strcmp (str, "string") == 0)
+ return MATCH_STRING;
+ if (strcmp (str, "int") == 0)
+ return MATCH_INT;
+ if (strcmp (str, "uint64") == 0)
+ return MATCH_UINT64;
+ if (strcmp (str, "bool") == 0)
+ return MATCH_BOOL;
+ if (strcmp (str, "exists") == 0)
+ return MATCH_EXISTS;
+ if (strcmp (str, "empty") == 0)
+ return MATCH_EMPTY;
+ if (strcmp (str, "is_ascii") == 0)
+ return MATCH_ISASCII;
+ if (strcmp (str, "is_absolute_path") == 0)
+ return MATCH_IS_ABS_PATH;
+ if (strcmp (str, "contains") == 0)
+ return MATCH_CONTAINS;
+ if (strcmp (str, "contains_ncase") == 0)
+ return MATCH_CONTAINS_NCASE;
+ if (strcmp (str, "prefix") == 0)
+ return MATCH_PREFIX;
+ if (strcmp (str, "prefix_ncase") == 0)
+ return MATCH_PREFIX_NCASE;
+ if (strcmp (str, "suffix") == 0)
+ return MATCH_SUFFIX;
+ if (strcmp (str, "suffix_ncase") == 0)
+ return MATCH_SUFFIX_NCASE;
+ if (strcmp (str, "compare_lt") == 0)
+ return MATCH_COMPARE_LT;
+ if (strcmp (str, "compare_le") == 0)
+ return MATCH_COMPARE_LE;
+ if (strcmp (str, "compare_gt") == 0)
+ return MATCH_COMPARE_GT;
+ if (strcmp (str, "compare_ge") == 0)
+ return MATCH_COMPARE_GE;
+ return MATCH_UNKNOWN;
+}
+
+static enum
+merge_type get_merge_type (const char *str)
+{
+ if (strcmp (str, "string") == 0)
+ return MERGE_STRING;
+ if (strcmp (str, "bool") == 0)
+ return MERGE_BOOLEAN;
+ if (strcmp (str, "int") == 0)
+ return MERGE_INT32;
+ if (strcmp (str, "unint64") == 0)
+ return MERGE_UINT64;
+ if (strcmp (str, "double") == 0)
+ return MERGE_DOUBLE;
+ if (strcmp (str, "strlist") == 0)
+ return MERGE_STRLIST;
+ if (strcmp (str, "copy_property") == 0)
+ return MERGE_COPY_PROPERTY;
+ if (strcmp (str, "remove") == 0)
+ return MERGE_REMOVE;
+ return MERGE_UNKNOWN;
+}
+
+#define ROUND32(len) ((len + 3) & ~0x03)
+
+static void pad32_write(int fd, off_t offset, void *data, size_t len)
+{
+ ssize_t result;
+ static char pad[3] = {0, 0, 0};
+
+ lseek(fd, offset, SEEK_SET);
+ result = write(fd, data, len);
+
+ if (result != (ssize_t) len)
+ DIE(("Disk write error"));
+
+ if ((offset + len) & 0x03) {
+ result = write(fd, pad, 4 - ((offset + len) & 0x03));
+
+ if (result != (ssize_t) (4 - ((offset + len) & 0x03)))
+ DIE(("Disk write error"));
+ }
+}
+
+static void init_rule_struct(struct rule *rule)
+{
+ memset(rule, 0, sizeof(struct rule));
+ rule->rule_size = sizeof(struct rule);
+ rule->rtype = RULE_UNKNOWN;
+ rule->type_match = MATCH_UNKNOWN;
+ rule->type_merge = MERGE_UNKNOWN;
+ rule->value_offset = offsetof(struct cache_header, empty_string);
+}
+
+/* stores key string to data file which we'll mmap next */
+static void store_key(struct fdi_context *fdi_ctx, const char *key)
+{
+ if (fdi_ctx->rule.rtype == RULE_UNKNOWN)
+ DIE(("I refuse to store garbage"));
+
+ if ((key == NULL) || (*key == '\0'))
+ DIE(("Key is not valid"));
+
+ fdi_ctx->rule.key_len = strlen(key) + 1;
+
+ pad32_write(fdi_ctx->cache_fd, fdi_ctx->position + sizeof(struct rule),
+ (void*)key, fdi_ctx->rule.key_len);
+
+ HAL_INFO(("Storing key '%s' at rule=%08lx", key, fdi_ctx->position));
+}
+
+/* stores value string to data file which we'll mmap next */
+static void store_value(struct fdi_context *fdi_ctx, const char *value, size_t value_len)
+{
+ off_t offset;
+ char * p;
+
+ if (fdi_ctx->rule.rtype == RULE_UNKNOWN)
+ DIE(("I refuse to store garbage"));
+
+ if (fdi_ctx->rule.key_len < 2)
+ DIE(("Key length is too small to be true"));
+
+ if ((value_len == 0) || (value == NULL) || (*value == '\0')) return;
+
+ offset = fdi_ctx->position + sizeof(struct rule) + ROUND32(fdi_ctx->rule.key_len);
+
+ if (fdi_ctx->rule.value_len == 0) {
+ fdi_ctx->rule.value_offset = offset;
+ fdi_ctx->rule.value_len = value_len + 1;
+ }
+ else {
+ offset += fdi_ctx->rule.value_len - 1;
+ fdi_ctx->rule.value_len += value_len;
+ }
+
+ pad32_write(fdi_ctx->cache_fd, offset, (void*)value, value_len);
+ pad32_write(fdi_ctx->cache_fd, offset + value_len, "", 1);
+
+ p = malloc(value_len + 1);
+
+ if(!p)
+ DIE(("Could not allocate %d bytes", value_len + 1));
+
+ memcpy(p, value, value_len);
+ p[value_len] = '\0';
+
+ HAL_INFO(("Storing value '%s', value_len=%d, at rule=%08lx, offset=%08lx",
+ p, value_len, fdi_ctx->position, offset));
+
+ free(p);
+}
+
+static void store_rule(struct fdi_context *fdi_ctx)
+{
+ if (fdi_ctx->rule.rtype == RULE_UNKNOWN)
+ DIE(("I refuse to store garbage"));
+
+ fdi_ctx->rule.rule_size = sizeof(struct rule) +
+ ROUND32(fdi_ctx->rule.key_len) +
+ ROUND32(fdi_ctx->rule.value_len);
+
+ pad32_write(fdi_ctx->cache_fd, fdi_ctx->position,
+ &fdi_ctx->rule, sizeof(struct rule));
+
+ HAL_INFO(("rule=%08lx, rule_size=%d, rtype=%d",
+ fdi_ctx->position, fdi_ctx->rule.rule_size, fdi_ctx->rule.rtype));
+
+ HAL_INFO((" jump_position=%08lx", fdi_ctx->rule.jump_position));
+
+ HAL_INFO((" key_len=%d, key_offset=%08lx",
+ fdi_ctx->rule.key_len, fdi_ctx->position + offsetof(struct rule, key)));
+
+ HAL_INFO((" value_len=%d, value_offset=%08lx",
+ fdi_ctx->rule.value_len, fdi_ctx->rule.value_offset));
+
+ init_rule_struct(&fdi_ctx->rule);
+}
+
+static void remember_jump_position(struct fdi_context *fdi_ctx)
+{
+ if (fdi_ctx->depth >= HAL_MAX_INDENT_DEPTH)
+ DIE(("Rule depth overflow"));
+ fdi_ctx->match_at_depth[fdi_ctx->depth++] = fdi_ctx->position;
+};
+
+static void set_jump_position(struct fdi_context *fdi_ctx)
+{
+ off_t offset;
+
+ if (fdi_ctx->depth <= 0)
+ DIE(("Rule depth underrun"));
+
+ fdi_ctx->depth--;
+ offset = lseek(fdi_ctx->cache_fd, 0, SEEK_END);
+ pad32_write(fdi_ctx->cache_fd,
+ fdi_ctx->match_at_depth[fdi_ctx->depth] + offsetof(struct rule, jump_position),
+ &offset, sizeof(fdi_ctx->rule.jump_position));
+
+ HAL_INFO(("modify rule=0x%08x, set jump to 0x%08x",
+ fdi_ctx->match_at_depth[fdi_ctx->depth], offset));
+}
+
+/* expat cb for start, e.g. <match foo=bar */
+static void
+start (void *data, const char *el, const char **attr)
+{
+ struct fdi_context *fdi_ctx = data;
+ int i;
+
+ /* we found a new tag, but old rule was not saved yet */
+ if (fdi_ctx->rule.rtype != RULE_UNKNOWN)
+ store_rule(fdi_ctx);
+
+ init_rule_struct(&fdi_ctx->rule);
+ fdi_ctx->rule.rtype = get_rule_type(el);
+ fdi_ctx->position = lseek(fdi_ctx->cache_fd, 0, SEEK_END);
+ if (fdi_ctx->rule.rtype == RULE_UNKNOWN) return;
+
+ /* get key and attribute for current rule */
+ for (i = 0; attr[i] != NULL; i+=2) {
+ if (strcmp (attr[i], "key") == 0) {
+ if (fdi_ctx->rule.key_len > 0)
+ DIE(("Bad rule: key already defined"));
+
+ store_key(fdi_ctx, attr[i + 1]);
+ continue;
+ }
+ if (fdi_ctx->rule.rtype == RULE_SPAWN) {
+ if (strcmp(attr[i], "udi") == 0) {
+ if (fdi_ctx->rule.key_len > 0)
+ DIE(("Bad rule: key already defined"));
+
+ store_key(fdi_ctx, attr[i + 1]);
+ continue;
+ }
+ /* TODO: is it error ??? */
+ continue;
+ } else if (fdi_ctx->rule.rtype == RULE_MATCH) {
+
+ if (fdi_ctx->rule.key_len == 0)
+ DIE(("Bad rule: value without a key"));
+
+ fdi_ctx->rule.type_match = get_match_type(attr[i]);
+
+ if (fdi_ctx->rule.type_match == MATCH_UNKNOWN)
+ DIE(("Bad rule: unknown type_match"));
+
+ store_value(fdi_ctx, attr[i + 1], strlen(attr[i + 1]));
+ continue;
+ } else {
+ if (strcmp(attr[i], "type") != 0){
+ /* TODO: is it error ??? */
+ continue;
+ }
+ fdi_ctx->rule.type_merge = get_merge_type(attr[i + 1]);
+
+ if (fdi_ctx->rule.type_merge == MERGE_UNKNOWN)
+ DIE(("Bad rule: unknown type_merge"));
+
+ continue;
+ }
+ }
+
+ if (fdi_ctx->rule.key_len == 0)
+ DIE(("Bad rule: key not found"));
+
+ /* match rules remember the current nesting and
+ the label to jump to if not matching */
+ if (fdi_ctx->rule.rtype == RULE_MATCH)
+ remember_jump_position(fdi_ctx);
+
+ return;
+}
+
+/* expat cb for character data, i.e. the text data in between tags */
+static void
+cdata (void *data, const char *s, int len){
+ struct fdi_context *fdi_ctx = data;
+
+ if (fdi_ctx->rule.rtype != RULE_MERGE &&
+ fdi_ctx->rule.rtype != RULE_PREPEND &&
+ fdi_ctx->rule.rtype != RULE_APPEND &&
+ fdi_ctx->rule.rtype != RULE_REMOVE &&
+ fdi_ctx->rule.rtype != RULE_SPAWN)
+ return;
+
+ store_value(fdi_ctx, s, len);
+}
+
+/* expat cb for end, e.g. </device> */
+static void
+end (void *data, const char *el){
+ struct fdi_context *fdi_ctx = data;
+ enum rule_type rtype = get_rule_type(el);
+
+ if (rtype == RULE_UNKNOWN) return;
+ if (rtype == RULE_MATCH){
+ set_jump_position(fdi_ctx);
+ return;
+ }
+
+ /* only valid if element is in the current context */
+ if (fdi_ctx->rule.rtype != rtype){
+ DIE(("Unexpected tag '%s'", el));
+ }
+ store_rule(fdi_ctx);
+}
+
+/* decompile an fdi file into a list of rules as this is quicker than opening then each time we want to search */
+static int
+rules_add_fdi_file (const char *filename, int fd){
+ struct fdi_context *fdi_ctx;
+ char *buf;
+ gsize buflen;
+ int rc;
+
+ if (!g_file_get_contents (filename, &buf, &buflen, NULL)) return -1;
+
+ /* create new context */
+ fdi_ctx = g_new0 (struct fdi_context, 1);
+ memset(fdi_ctx, 0, sizeof(struct fdi_context));
+ init_rule_struct(&fdi_ctx->rule);
+ fdi_ctx->cache_fd = fd;
+
+ XML_Parser parser = XML_ParserCreate (NULL);
+ if (parser == NULL) {
+ fprintf (stderr, "Couldn't allocate memory for parser\n");
+ return -1;
+ }
+ XML_SetUserData (parser, fdi_ctx);
+ XML_SetElementHandler (parser, start, end);
+ XML_SetCharacterDataHandler (parser, cdata);
+ rc = XML_Parse (parser, buf, buflen, 1);
+ if (rc == 0)
+ fprintf (stderr, "Parse error at line %i:\n%s\n",
+ (int) XML_GetCurrentLineNumber (parser),
+ XML_ErrorString (XML_GetErrorCode (parser)));
+ XML_ParserFree (parser);
+ g_free (buf);
+
+ /* insert last dummy rule into list */
+ init_rule_struct(&fdi_ctx->rule);
+ fdi_ctx->rule.rtype = RULE_EOF;
+ fdi_ctx->position = lseek(fdi_ctx->cache_fd, 0, SEEK_END);
+ store_key(fdi_ctx, filename);
+ store_value(fdi_ctx, "", 0);
+ store_rule(fdi_ctx);
+
+ g_free (fdi_ctx);
+
+ if (rc == 0) return -1;
+ return lseek(fd, 0, SEEK_END);
+}
+
+
+/* recurse a directory tree, searching and adding fdi files */
+static int
+rules_search_and_add_fdi_files (const char *dir, int fd)
+{
+ int i;
+ int num_entries;
+ struct dirent **name_list;
+
+ num_entries = scandir (dir, &name_list, 0, _alphasort);
+ if (num_entries == -1)
+ return -1;
+
+ for (i = num_entries - 1; i >= 0; i--) {
+ int len;
+ char *filename;
+ gchar *full_path;
+
+ filename = name_list[i]->d_name;
+ len = strlen (filename);
+ full_path = g_strdup_printf ("%s/%s", dir, filename);
+ if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
+ if (len >= 5 && strcmp(&filename[len - 4], ".fdi") == 0) {
+ int fdi_rules_size;
+ fdi_rules_size = rules_add_fdi_file (full_path, fd);
+ if (fdi_rules_size < 0)
+ HAL_WARNING (("error processing fdi file '%s'", full_path));
+ }
+ } else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR)) && filename[0] != '.') {
+ int num_bytes;
+ char *dirname;
+
+ num_bytes = len + strlen (dir) + 1 + 1;
+ dirname = (char *) malloc (num_bytes);
+ if (dirname == NULL)
+ break;
+
+ snprintf (dirname, num_bytes, "%s/%s", dir, filename);
+ rules_search_and_add_fdi_files (dirname, fd);
+ free (dirname);
+ }
+ g_free (full_path);
+ free (name_list[i]);
+ }
+
+ for (; i >= 0; i--) free (name_list[i]);
+ free (name_list);
+ return 0;
+}
+
+
+int haldc_is_verbose = 0;
+int haldc_use_syslog = 0;
+int haldc_force_recreate = 0;
+
+
+static void
+di_rules_init (void)
+{
+ char * cachename;
+ int fd;
+ struct cache_header header;
+ struct stat st;
+ char namebuf [PATH_MAX+1];
+ char *hal_fdi_source_preprobe = getenv ("HAL_FDI_SOURCE_PREPROBE");
+ char *hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
+ char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
+
+ cachename = getenv ("HAL_FDI_CACHE_NAME");
+ if(!cachename) cachename = CACHE_FILE;
+ HAL_INFO (("Loading rules"));
+
+ if(haldc_force_recreate && !stat(cachename, &st)) {
+ strncpy(namebuf, cachename, PATH_MAX);
+ strncat(namebuf, ".bak", PATH_MAX);
+ if(rename(cachename, namebuf) < 0)
+ DIE(("Unable to rename file %s to file %s", cachename, namebuf));
+ }
+
+ fd = open(cachename, O_CREAT|O_RDWR|O_EXCL|O_TRUNC, 0644);
+ if(fd < 0) DIE(("Unable to open fdi cache %s file for writing: %s",
+ cachename, strerror(errno)));
+
+ memset(&header, 0, sizeof(struct cache_header));
+ pad32_write(fd, 0, &header, sizeof(struct cache_header));
+
+ header.fdi_rules_preprobe = lseek(fd, 0, SEEK_END);
+ if (hal_fdi_source_preprobe != NULL)
+ rules_search_and_add_fdi_files (hal_fdi_source_preprobe, fd);
+ else{
+ rules_search_and_add_fdi_files (PACKAGE_DATA_DIR "/hal/fdi/preprobe", fd);
+ rules_search_and_add_fdi_files (PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", fd);
+ }
+
+ header.fdi_rules_information = lseek(fd, 0, SEEK_END);
+ if (hal_fdi_source_information != NULL)
+ rules_search_and_add_fdi_files (hal_fdi_source_information, fd);
+ else {
+ rules_search_and_add_fdi_files (PACKAGE_DATA_DIR "/hal/fdi/information", fd);
+ rules_search_and_add_fdi_files (PACKAGE_SYSCONF_DIR "/hal/fdi/information", fd);
+ }
+
+ header.fdi_rules_policy = lseek(fd, 0, SEEK_END);
+ if (hal_fdi_source_policy != NULL)
+ rules_search_and_add_fdi_files (hal_fdi_source_policy, fd);
+ else {
+ rules_search_and_add_fdi_files (PACKAGE_DATA_DIR "/hal/fdi/policy", fd);
+ rules_search_and_add_fdi_files (PACKAGE_SYSCONF_DIR "/hal/fdi/policy", fd);
+ }
+
+ header.all_rules_size = lseek(fd, 0, SEEK_END);
+ pad32_write(fd, 0, &header, sizeof(struct cache_header));
+ close(fd);
+
+ HAL_INFO(("preprobe: offset=%08lx, size=%d", header.fdi_rules_preprobe,
+ header.fdi_rules_information - header.fdi_rules_preprobe));
+ HAL_INFO(("information: offset=%08lx, size=%d", header.fdi_rules_information,
+ header.fdi_rules_policy - header.fdi_rules_information));
+ HAL_INFO(("policy: offset=%08lx, size=%d", header.fdi_rules_policy,
+ header.all_rules_size - header.fdi_rules_policy));
+
+ HAL_INFO (("Loading rules done (occupying %d bytes)", header.all_rules_size));
+}
+
+/** Print out program usage.
+ *
+ */
+static void
+usage ()
+{
+ fprintf (stderr, "\n" "usage : hald-cache [--verbose=yes|no] [--use-syslog] [--help]\n");
+ fprintf (stderr,
+ "\n"
+ " --verbose=yes|no Print out debug (overrides HALD_VERBOSE).\n"
+ " --use-syslog Print out debug messages to syslog instead of\n"
+ " stderr. Use this option to get debug messages.\n"
+ " --force Force regeneration of cache.\n"
+ " --help Show this information and exit.\n"
+ " --version Output version information and exit.\n"
+ "\n"
+ "hald-cache is a tool to generate binary cache from FDI files.\n"
+ "\n"
+ "For more information visit http://freedesktop.org/Software/hal\n"
+ "\n");
+}
+
+
+int main(int argc, char * argv[])
+{
+ openlog ("hald-cache", LOG_PID, LOG_DAEMON);
+
+ while (1) {
+ int c;
+ int option_index = 0;
+ const char *opt;
+ static struct option long_options[] = {
+ {"exit-after-probing", 0, NULL, 0},
+ {"daemon", 1, NULL, 0},
+ {"verbose", 1, NULL, 0},
+ {"retain-privileges", 0, NULL, 0},
+ {"use-syslog", 0, NULL, 0},
+ {"help", 0, NULL, 0},
+ {"version", 0, NULL, 0},
+ {"force", 0, NULL, 0},
+ {NULL, 0, NULL, 0}
+ };
+
+ c = getopt_long (argc, argv, "",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 0:
+ opt = long_options[option_index].name;
+
+ if (strcmp (opt, "help") == 0) {
+ usage ();
+ return 0;
+ } else if (strcmp (opt, "version") == 0) {
+ fprintf (stderr, "HAL package version: " PACKAGE_VERSION "\n");
+ return 0;
+ } else if (strcmp (opt, "verbose") == 0) {
+ if (strcmp ("yes", optarg) == 0) {
+ haldc_is_verbose = 1;
+ } else if (strcmp ("no", optarg) == 0) {
+ haldc_is_verbose = 0;
+ } else {
+ usage ();
+ return 1;
+ }
+ } else if (strcmp (opt, "use-syslog") == 0) {
+ haldc_use_syslog = 1;
+ } else if (strcmp (opt, "force") == 0) {
+ haldc_force_recreate = 1;
+ }
+
+ break;
+
+ default:
+ usage ();
+ return 1;
+ break;
+ }
+ }
+
+ if (haldc_is_verbose)
+ logger_enable ();
+ else
+ logger_disable ();
+
+ if (haldc_use_syslog)
+ logger_enable_syslog ();
+ else
+ logger_disable_syslog ();
+
+ di_rules_init();
+ return 0;
+}
diff --git a/hald/device_info.c b/hald/device_info.c
index e6077f8..0dd1cdc 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -1,11 +1,13 @@
/***************************************************************************
* CVSID: $Id$
*
- * device_store.c : Parse .fdi files and match/merge device properties.
+ * device_info.c : match/merge device properties.
*
* Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
* Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
* Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
*
* Licensed under the Academic Free License version 2.1
*
@@ -38,246 +40,24 @@
#include <assert.h>
#include <dbus/dbus.h>
#include <dbus/dbus-glib.h>
+#include <sys/types.h>
#include <sys/stat.h>
+#include <fcntl.h>
#include <math.h>
+#include <sys/mman.h>
+#include <errno.h>
#include "hald.h"
#include "logger.h"
+#include "mmap_cache.h"
#include "device_info.h"
#include "device_store.h"
#include "util.h"
+#include "rule.h"
-#define MAX_INDENT_DEPTH 64
+void *rules_ptr = NULL;
-/* pre-parsed rules to keep in memory */
-static GSList *fdi_rules_preprobe;
-static GSList *fdi_rules_information;
-static GSList *fdi_rules_policy;
-
-/* rule type to process */
-enum rule_type {
- RULE_UNKNOWN,
- RULE_MATCH,
- RULE_MERGE,
- RULE_APPEND,
- RULE_PREPEND,
- RULE_REMOVE,
- RULE_CLEAR,
- RULE_SPAWN,
- RULE_EOF,
-};
-
-/* type of merge command */
-enum merge_type {
- MERGE_UNKNOWN,
- MERGE_STRING,
- MERGE_BOOLEAN,
- MERGE_INT32,
- MERGE_UINT64,
- MERGE_DOUBLE,
- MERGE_COPY_PROPERTY,
- MERGE_STRLIST,
- MERGE_REMOVE,
-};
-
-/* type of match command */
-enum
-match_type {
- MATCH_UNKNOWN,
- MATCH_STRING,
- MATCH_INT,
- MATCH_UINT64,
- MATCH_BOOL,
- MATCH_EXISTS,
- MATCH_EMPTY,
- MATCH_ISASCII,
- MATCH_IS_ABS_PATH,
- MATCH_CONTAINS,
- MATCH_CONTAINS_NCASE,
- MATCH_PREFIX,
- MATCH_PREFIX_NCASE,
- MATCH_SUFFIX,
- MATCH_SUFFIX_NCASE,
- MATCH_COMPARE_LT,
- MATCH_COMPARE_LE,
- MATCH_COMPARE_GT,
- MATCH_COMPARE_GE,
-};
-
-/* a "rule" structure that is a generic node of the fdi file */
-struct rule {
- /* typ of tule in the list */
- enum rule_type rtype;
-
- /* all rules have a key */
- char *key;
-
- /* "match" or "merge" rule */
- enum match_type type_match;
- enum merge_type type_merge;
-
- char *value;
- int value_len;
-
- /* if rule does not match, skip to this rule */
- struct rule *next_rule;
-};
-
-/* ctx of the current fdi file used for parsing */
-struct fdi_context {
- int depth;
- struct rule *match_at_depth[MAX_INDENT_DEPTH];
-
- /* current rule */
- struct rule *rule;
-
- int fdi_rule_size;
-
- /* all rules */
- GSList* rules;
-};
-
-static enum
-rule_type get_rule_type (const char *str)
-{
- if (strcmp (str, "match") == 0)
- return RULE_MATCH;
- if (strcmp (str, "merge") == 0)
- return RULE_MERGE;
- if (strcmp (str, "append") == 0)
- return RULE_APPEND;
- if (strcmp (str, "prepend") == 0)
- return RULE_PREPEND;
- if (strcmp (str, "remove") == 0)
- return RULE_REMOVE;
- if (strcmp (str, "clear") == 0)
- return RULE_CLEAR;
- if (strcmp (str, "spawn") == 0)
- return RULE_SPAWN;
- return RULE_UNKNOWN;
-}
-
-/*
-static char *
-get_rule_type_str (enum rule_type type)
-{
- switch (type) {
- case RULE_MATCH:
- return "match";
- case RULE_MERGE:
- return "merge";
- case RULE_APPEND:
- return "append";
- case RULE_PREPEND:
- return "prepend";
- case RULE_REMOVE:
- return "remove";
- case RULE_CLEAR:
- return "clear";
- case RULE_SPAWN:
- return "spawn";
- case RULE_EOF:
- return "eof";
- case RULE_UNKNOWN:
- return "unknown rule type";
- }
- return "invalid rule type";
-}
-*/
-
-static enum
-merge_type get_merge_type (const char *str)
-{
- if (strcmp (str, "string") == 0)
- return MERGE_STRING;
- if (strcmp (str, "bool") == 0)
- return MERGE_BOOLEAN;
- if (strcmp (str, "int") == 0)
- return MERGE_INT32;
- if (strcmp (str, "unint64") == 0)
- return MERGE_UINT64;
- if (strcmp (str, "double") == 0)
- return MERGE_DOUBLE;
- if (strcmp (str, "strlist") == 0)
- return MERGE_STRLIST;
- if (strcmp (str, "copy_property") == 0)
- return MERGE_COPY_PROPERTY;
- if (strcmp (str, "remove") == 0)
- return MERGE_REMOVE;
- return MERGE_UNKNOWN;
-}
-
-/*
-static char *
-get_merge_type_str (enum merge_type type)
-{
- switch (type) {
- case MERGE_STRING:
- return "string";
- case MERGE_BOOLEAN:
- return "bool";
- case MERGE_INT32:
- return "int";
- case MERGE_UINT64:
- return "unint64";
- case MERGE_DOUBLE:
- return "double";
- case MERGE_STRLIST:
- return "strlist";
- case MERGE_COPY_PROPERTY:
- return "copy_property";
- case MERGE_REMOVE:
- return "remove";
- case MERGE_UNKNOWN:
- return "unknown merge type";
- }
- return "invalid merge type";
-}
-*/
-
-static enum
-match_type get_match_type(const char *str)
-{
- if (strcmp (str, "string") == 0)
- return MATCH_STRING;
- if (strcmp (str, "int") == 0)
- return MATCH_INT;
- if (strcmp (str, "uint64") == 0)
- return MATCH_UINT64;
- if (strcmp (str, "bool") == 0)
- return MATCH_BOOL;
- if (strcmp (str, "exists") == 0)
- return MATCH_EXISTS;
- if (strcmp (str, "empty") == 0)
- return MATCH_EMPTY;
- if (strcmp (str, "is_ascii") == 0)
- return MATCH_ISASCII;
- if (strcmp (str, "is_absolute_path") == 0)
- return MATCH_IS_ABS_PATH;
- if (strcmp (str, "contains") == 0)
- return MATCH_CONTAINS;
- if (strcmp (str, "contains_ncase") == 0)
- return MATCH_CONTAINS_NCASE;
- if (strcmp (str, "prefix") == 0)
- return MATCH_PREFIX;
- if (strcmp (str, "prefix_ncase") == 0)
- return MATCH_PREFIX_NCASE;
- if (strcmp (str, "suffix") == 0)
- return MATCH_SUFFIX;
- if (strcmp (str, "suffix_ncase") == 0)
- return MATCH_SUFFIX_NCASE;
- if (strcmp (str, "compare_lt") == 0)
- return MATCH_COMPARE_LT;
- if (strcmp (str, "compare_le") == 0)
- return MATCH_COMPARE_LE;
- if (strcmp (str, "compare_gt") == 0)
- return MATCH_COMPARE_GT;
- if (strcmp (str, "compare_ge") == 0)
- return MATCH_COMPARE_GE;
- return MATCH_UNKNOWN;
-}
-
-/*
+#ifdef DUMP_RULES
static char *
get_match_type_str (enum match_type type)
{
@@ -323,7 +103,7 @@ get_match_type_str (enum match_type type
}
return "invalid match type";
}
-*/
+#endif
/** Resolve a udi-property path as used in .fdi files.
*
@@ -475,7 +255,7 @@ handle_match (struct rule *rule, HalDevi
char udi_to_check[HAL_PATH_MAX];
char prop_to_check[HAL_PATH_MAX];
const char *key = rule->key;
- const char *value = rule->value;
+ const char *value = (char *)RULES_PTR(rule->value_offset);
/* Resolve key paths like 'someudi/foo/bar/baz:prop.name' '@prop.here.is.an.udi:with.prop.name' */
if (!resolve_udiprop_path (key,
@@ -870,7 +650,7 @@ static gboolean
handle_merge (struct rule *rule, HalDevice *d)
{
const char *key = rule->key;
- const char *value = rule->value;
+ const char *value = (char *)RULES_PTR(rule->value_offset);
if (rule->rtype == RULE_MERGE) {
@@ -1044,375 +824,53 @@ handle_merge (struct rule *rule, HalDevi
return TRUE;
}
-/* for each node, free memory and it's own list of nodes */
-static void
-rules_cleanup_list (GSList *fdi_rules)
-{
- GSList *elem;
-
- for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
- struct rule *rule = elem->data;
-
- g_free (rule->key);
- g_free (rule->value);
- g_free (rule);
- }
- g_slist_free (fdi_rules);
- fdi_rules = NULL;
-}
-
-/* expat cb for start, e.g. <match foo=bar */
-static void
-start (void *data, const char *el, const char **attr)
-{
- struct fdi_context *fdi_ctx = data;
- enum rule_type rtype = get_rule_type (el);
- int i;
-
- if (rtype == RULE_UNKNOWN)
- return;
-
- if (fdi_ctx->rule == NULL)
- return;
-
- /* get key and attribute for current rule */
- for (i = 0; attr[i] != NULL; i+=2) {
- if (strcmp (attr[i], "key") == 0) {
- fdi_ctx->rule->key = g_strdup (attr[1]);
- continue;
- }
- if (rtype == RULE_SPAWN) {
- if (strcmp (attr[i], "udi") == 0) {
- fdi_ctx->rule->key = g_strdup (attr[1]);
- continue;
- }
- } else if (rtype == RULE_MATCH) {
- fdi_ctx->rule->type_match = get_match_type (attr[i]);
- if (fdi_ctx->rule->type_match == MATCH_UNKNOWN)
- continue;
- fdi_ctx->rule->value = g_strdup (attr[i+1]);
- } else {
- if (strcmp (attr[i], "type") != 0)
- continue;
- fdi_ctx->rule->type_merge = get_merge_type (attr[i+1]);
- if (fdi_ctx->rule->type_merge == MERGE_UNKNOWN)
- return;
- }
- }
-
- if (fdi_ctx->rule->key[0] == '\0')
- return;
-
- fdi_ctx->rule->rtype = rtype;
-
- /* match rules remember the current nesting and the label to jump to if not matching */
- if (rtype == RULE_MATCH) {
- /* remember current nesting */
- fdi_ctx->depth++;
-
- /* remember rule at nesting level nesting */
- fdi_ctx->match_at_depth[fdi_ctx->depth] = fdi_ctx->rule;
-
- /* insert match rule into list and get new rule */
- fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
- fdi_ctx->rule = g_new0 (struct rule ,1);
- }
-}
-
-/* expat cb for character data, i.e. the text data in between tags */
-static void
-cdata (void *data, const char *s, int len)
-{
- struct fdi_context *fdi_ctx = data;
-
- if (fdi_ctx->rule == NULL)
- return;
-
- if (fdi_ctx->rule->rtype != RULE_MERGE &&
- fdi_ctx->rule->rtype != RULE_PREPEND &&
- fdi_ctx->rule->rtype != RULE_APPEND &&
- fdi_ctx->rule->rtype != RULE_REMOVE &&
- fdi_ctx->rule->rtype != RULE_SPAWN)
- return;
-
- if (len < 1)
- return;
-
- /* copy cdata in current context */
- fdi_ctx->rule->value = g_realloc (fdi_ctx->rule->value, fdi_ctx->rule->value_len + len+1);
- memcpy (&fdi_ctx->rule->value[fdi_ctx->rule->value_len], s, len);
- fdi_ctx->rule->value_len += len;
- fdi_ctx->rule->value[fdi_ctx->rule->value_len] = '\0';
-}
-
-/* expat cb for end, e.g. </device> */
-static void
-end (void *data, const char *el)
-{
- struct fdi_context *fdi_ctx = data;
- enum rule_type rtype = get_rule_type (el);
-
- if (rtype == RULE_UNKNOWN)
- return;
-
- if (rtype == RULE_MATCH) {
- if (fdi_ctx->depth <= 0)
- return;
-
- /* get corresponding match rule and set the rule to skip to */
- fdi_ctx->match_at_depth[fdi_ctx->depth]->next_rule = fdi_ctx->rule;
- fdi_ctx->depth--;
- return;
- }
-
- /* only valid if element is in the current context */
- if (fdi_ctx->rule->rtype != rtype)
- return;
-
- /* set empty value to empty string */
- if (fdi_ctx->rule->value == NULL)
- fdi_ctx->rule->value = g_strdup ("");
-
- if (fdi_ctx->fdi_rule_size >= 0) {
- fdi_ctx->fdi_rule_size +=
- sizeof (struct rule) +
- strlen (fdi_ctx->rule->key) +
- fdi_ctx->rule->value_len;
- }
-
- /* insert merge rule into list and get new rule */
- fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
- fdi_ctx->rule = g_new0 (struct rule, 1);
-}
-
-/* decompile an fdi file into a list of rules as this is quicker than opening then each time we want to search */
-static int
-rules_add_fdi_file (GSList **fdi_rules, const char *filename, gboolean compute_rule_size)
-{
- struct fdi_context *fdi_ctx;
- char *buf;
- gsize buflen;
- int rc;
- int fdi_rule_size;
-
- if (!g_file_get_contents (filename, &buf, &buflen, NULL))
- return -1;
-
- /* get context and first rule */
- fdi_ctx = g_new0 (struct fdi_context ,1);
- fdi_ctx->rule = g_new0 (struct rule ,1);
- fdi_ctx->fdi_rule_size = compute_rule_size ? 0 : -1;
-
- XML_Parser parser = XML_ParserCreate (NULL);
- if (parser == NULL) {
- fprintf (stderr, "Couldn't allocate memory for parser\n");
- return -1;
- }
- XML_SetUserData (parser, fdi_ctx);
- XML_SetElementHandler (parser, start, end);
- XML_SetCharacterDataHandler (parser, cdata);
- rc = XML_Parse (parser, buf, buflen, 1);
- if (rc == 0)
- fprintf (stderr, "Parse error at line %i:\n%s\n",
- (int) XML_GetCurrentLineNumber (parser),
- XML_ErrorString (XML_GetErrorCode (parser)));
- XML_ParserFree (parser);
- g_free (buf);
-
- /* insert last dummy rule into list */
- fdi_ctx->rule->rtype = RULE_EOF;
- fdi_ctx->rule->key = g_strdup (filename);
- fdi_ctx->rules = g_slist_append (fdi_ctx->rules, fdi_ctx->rule);
-
- /* add rules to external list */
- if (rc == 0)
- rules_cleanup_list (fdi_ctx->rules);
- else
- *fdi_rules = g_slist_concat (*fdi_rules, fdi_ctx->rules);
-
- fdi_rule_size = (gint64) fdi_ctx->fdi_rule_size;
-
- g_free (fdi_ctx);
-
- if (rc == 0)
- return -1;
-
- return compute_rule_size ? fdi_rule_size : 0;
-}
-
-/* modified alphasort to count downwards */
-static int
-#ifdef __GLIBC__
-_alphasort(const void *a, const void *b)
-#else
-_alphasort(const struct dirent **a, const struct dirent **b)
-#endif
-{
- return -alphasort (a, b);
-}
-
-/* recurse a directory tree, searching and adding fdi files */
-static int
-rules_search_and_add_fdi_files (GSList **fdi_rules, const char *dir, int *rules_size)
-{
- int i;
- int num_entries;
- struct dirent **name_list;
-
- num_entries = scandir (dir, &name_list, 0, _alphasort);
- if (num_entries == -1)
- return -1;
-
- for (i = num_entries - 1; i >= 0; i--) {
- int len;
- char *filename;
- gchar *full_path;
-
- filename = name_list[i]->d_name;
- len = strlen (filename);
- full_path = g_strdup_printf ("%s/%s", dir, filename);
- if (g_file_test (full_path, (G_FILE_TEST_IS_REGULAR))) {
- if (len >= 5 && strcmp(&filename[len - 4], ".fdi") == 0) {
- int fdi_rules_size;
- fdi_rules_size = rules_add_fdi_file (fdi_rules, full_path, rules_size != NULL);
- if (fdi_rules_size >= 0) {
- if (rules_size != NULL) {
- *rules_size += fdi_rules_size;
- HAL_INFO (("fdi file '%s' -> %d bytes of rules",
- full_path, fdi_rules_size));
- }
- } else {
- HAL_WARNING (("error processing fdi file '%s'", full_path));
- }
- }
- } else if (g_file_test (full_path, (G_FILE_TEST_IS_DIR)) && filename[0] != '.') {
- int num_bytes;
- char *dirname;
-
- num_bytes = len + strlen (dir) + 1 + 1;
- dirname = (char *) malloc (num_bytes);
- if (dirname == NULL)
- break;
-
- snprintf (dirname, num_bytes, "%s/%s", dir, filename);
- rules_search_and_add_fdi_files (fdi_rules, dirname, rules_size);
- free (dirname);
- }
- g_free (full_path);
- free (name_list[i]);
- }
-
- for (; i >= 0; i--) {
- free (name_list[i]);
- }
-
- free (name_list);
- return 0;
-}
-
-/* print the rules to screen, mainly useful for debugging */
-#if 0
-static void
-rules_dump (GSList *fdi_rules)
-{
- GSList *elem;
-
- for (elem = fdi_rules; elem != NULL; elem = g_slist_next (elem)) {
- struct rule *rule = elem->data;
-
- if (rule->rtype == RULE_EOF) {
- printf ("%p: eof %s\n", rule, rule->key);
- } else if (rule->rtype == RULE_MATCH) {
- printf ("\n");
- printf ("%p: match '%s' (%s) '%s' (skip to %p)\n",
- rule, rule->key, get_match_type_str (rule->type_match),
- rule->value, rule->next_rule);
- } else {
- printf ("%p: %s '%s' (%s) '%s'\n",
- rule, get_rule_type_str (rule->rtype), rule->key,
- get_merge_type_str (rule->type_merge), rule->value);
- }
+static struct rule *di_next(struct rule *rule){
+ struct cache_header *header = (struct cache_header*) RULES_PTR(0);
+ size_t offset = (char *)rule - (char*)rules_ptr;
+ size_t next = offset + rule->rule_size;
+
+ if (((offset >= header->fdi_rules_preprobe) && (next < header->fdi_rules_information)) ||
+ ((offset >= header->fdi_rules_information) && (next < header->fdi_rules_policy)) ||
+ ((offset >= header->fdi_rules_policy) && (next < header->all_rules_size))){
+ return (struct rule*) RULES_PTR(next);
+ }
+ return NULL;
+}
+
+static struct rule *di_jump(struct rule *rule){
+ struct cache_header *header = (struct cache_header*) RULES_PTR(0);
+ size_t offset = (char *)rule - (char*)rules_ptr;
+ size_t next = rule->jump_position;
+
+ if (next == 0) return NULL;
+ if (((offset >= header->fdi_rules_preprobe) && (next < header->fdi_rules_information)) ||
+ ((offset >= header->fdi_rules_information) && (next < header->fdi_rules_policy)) ||
+ ((offset >= header->fdi_rules_policy) && (next < header->all_rules_size))){
+ return (struct rule*) RULES_PTR(next);
}
+ return NULL;
}
-#endif
-
-/* setup the location of the rules */
-void
-di_rules_init (void)
-{
- int size;
- char *hal_fdi_source_preprobe = getenv ("HAL_FDI_SOURCE_PREPROBE");
- char *hal_fdi_source_information = getenv ("HAL_FDI_SOURCE_INFORMATION");
- char *hal_fdi_source_policy = getenv ("HAL_FDI_SOURCE_POLICY");
-
- HAL_INFO (("Loading rules"));
-
- size = 0;
-
- if (hal_fdi_source_preprobe != NULL)
- rules_search_and_add_fdi_files (&fdi_rules_preprobe, hal_fdi_source_preprobe, &size);
- else {
- rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_DATA_DIR "/hal/fdi/preprobe", &size);
- rules_search_and_add_fdi_files (&fdi_rules_preprobe, PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", &size);
- }
-
- if (hal_fdi_source_information != NULL)
- rules_search_and_add_fdi_files (&fdi_rules_information, hal_fdi_source_information, &size);
- else {
- rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_DATA_DIR "/hal/fdi/information", &size);
- rules_search_and_add_fdi_files (&fdi_rules_information, PACKAGE_SYSCONF_DIR "/hal/fdi/information", &size);
- }
-
- if (hal_fdi_source_policy != NULL)
- rules_search_and_add_fdi_files (&fdi_rules_policy, hal_fdi_source_policy, &size);
- else {
- rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_DATA_DIR "/hal/fdi/policy", &size);
- rules_search_and_add_fdi_files (&fdi_rules_policy, PACKAGE_SYSCONF_DIR "/hal/fdi/policy", &size);
- }
- /* dump the rules (commented out as this is expensive) */
- /*rules_dump (fdi_rules_preprobe);
- rules_dump (fdi_rules_information);
- rules_dump (fdi_rules_policy);
- */
-
- HAL_INFO (("Loading rules done (occupying %d bytes)", size));
-}
-
-/* cleanup the rules */
-void
-di_rules_cleanup (void)
-{
- rules_cleanup_list (fdi_rules_preprobe);
- rules_cleanup_list (fdi_rules_information);
- rules_cleanup_list (fdi_rules_policy);
- fdi_rules_preprobe = NULL;
- fdi_rules_information = NULL;
- fdi_rules_policy = NULL;
-}
/* process a match and merge comand for a device */
static void
-rules_match_and_merge_device (GSList *fdi_rules, HalDevice *d)
+rules_match_and_merge_device (void *fdi_rules_list, HalDevice *d)
{
- GSList *elem;
-
- if (fdi_rules == NULL) {
- di_rules_cleanup ();
- di_rules_init ();
- }
-
- elem = fdi_rules;
- while (elem != NULL) {
- struct rule *rule = elem->data;
+ struct rule *rule = fdi_rules_list;
+ while (rule != NULL){
+ HAL_INFO(("== Iterating rules =="));
switch (rule->rtype) {
case RULE_MATCH:
/* skip non-matching rules block */
- /*HAL_INFO(("%p match '%s' at %s", rule, rule->key, hal_device_get_udi (d)));*/
+ HAL_INFO(("%p match '%s' at %s", rule, rule->key, hal_device_get_udi (d)));
if (!handle_match (rule, d)) {
- /*HAL_INFO(("no match, skip to rule %s (%p)", get_rule_type_str (rule->next_rule->rtype), rule->next_rule));*/
- elem = g_slist_find (elem, rule->next_rule);
+ HAL_INFO(("no match, skip to rule (%llx)", rule->jump_position));
+ rule = di_jump(rule);
+
+ if(rule == NULL)
+ DIE(("Rule is NULL on jump"));
+
continue;
}
break;
@@ -1435,28 +893,48 @@ rules_match_and_merge_device (GSList *fd
HAL_WARNING(("Unhandled rule (%i)!", rule->rtype));
break;
}
- elem = g_slist_next (elem);
+ rule = di_next(rule);
}
}
+
/* merge the device info type, either preprobe, info or policy */
gboolean
-di_search_and_merge (HalDevice *d, DeviceInfoType type)
-{
+di_search_and_merge (HalDevice *d, DeviceInfoType type){
+ struct cache_header *header = (struct cache_header*) RULES_PTR(0);
+
switch (type) {
case DEVICE_INFO_TYPE_PREPROBE:
- /*HAL_INFO(("apply fdi preprobe to device %p", d));*/
- rules_match_and_merge_device (fdi_rules_preprobe, d);
+ /* Checking if we have at least one preprobe rule */
+ if(header->fdi_rules_information > header->fdi_rules_preprobe)
+ {
+ HAL_INFO(("preprobe rules offset: %ld", header->fdi_rules_preprobe));
+ HAL_INFO(("preprobe rules size: %ld",
+ header->fdi_rules_information - header->fdi_rules_preprobe));
+ rules_match_and_merge_device (RULES_PTR(header->fdi_rules_preprobe), d);
+ }
break;
case DEVICE_INFO_TYPE_INFORMATION:
- /*HAL_INFO(("apply fdi info to device %p", d));*/
- rules_match_and_merge_device (fdi_rules_information, d);
+ /* Checking if we have at least one information rule */
+ if(header->fdi_rules_policy > header->fdi_rules_information)
+ {
+ HAL_INFO(("information rules offset: %ld", header->fdi_rules_information));
+ HAL_INFO(("information rules size: %ld",
+ header->fdi_rules_policy - header->fdi_rules_information));
+ rules_match_and_merge_device (RULES_PTR(header->fdi_rules_information), d);
+ }
break;
case DEVICE_INFO_TYPE_POLICY:
- /*HAL_INFO(("apply fdi policy to device %p", d));*/
- rules_match_and_merge_device (fdi_rules_policy, d);
+ /* Checking if we have at least one policy rule */
+ if(header->all_rules_size > header->fdi_rules_policy)
+ {
+ HAL_INFO(("policy rules offset: %ld", header->fdi_rules_policy));
+ HAL_INFO(("policy rules size: %ld",
+ header->all_rules_size - header->fdi_rules_policy));
+ rules_match_and_merge_device (RULES_PTR(header->fdi_rules_policy), d);
+ }
break;
default:
diff --git a/hald/device_info.h b/hald/device_info.h
index 24b1567..3c1cbb5 100644
--- a/hald/device_info.h
+++ b/hald/device_info.h
@@ -32,6 +32,7 @@
#include "device_store.h"
+
typedef enum {
DEVICE_INFO_TYPE_PREPROBE,
DEVICE_INFO_TYPE_INFORMATION,
diff --git a/hald/hald.c b/hald/hald.c
index d946c4e..8c7875b 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -59,6 +59,7 @@
#include "util.h"
#include "hald_runner.h"
#include "util_helper.h"
+#include "mmap_cache.h"
static void delete_pid(void)
{
@@ -418,6 +419,7 @@ main (int argc, char *argv[])
g_strlcat (newpath, PACKAGE_SCRIPT_DIR, sizeof (newpath));
setenv ("PATH", newpath, TRUE);
+
while (1) {
int c;
@@ -502,6 +504,8 @@ main (int argc, char *argv[])
loop = g_main_loop_new (NULL, FALSE);
HAL_INFO ((PACKAGE_STRING));
+
+ cache_coherency_check();
if (opt_become_daemon) {
int child_pid;
@@ -614,6 +618,9 @@ main (int argc, char *argv[])
hald_is_initialising = TRUE;
+ /* Init FDI files */
+ di_rules_init();
+
/* detect devices */
osspec_probe ();
diff --git a/hald/mmap_cache.c b/hald/mmap_cache.c
new file mode 100644
index 0000000..e43c6da
--- /dev/null
+++ b/hald/mmap_cache.c
@@ -0,0 +1,160 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * mmap_cache.c : FDI cache routines.
+ *
+ * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <dirent.h>
+
+#include "logger.h"
+#include "rule.h"
+#include "mmap_cache.h"
+
+extern void *rules_ptr;
+
+void di_rules_init(void){
+ struct cache_header *header;
+ char *cachename;
+ int fd;
+ struct stat statbuf;
+
+ cachename = getenv ("HAL_FDI_CACHE_NAME");
+ if(!cachename) cachename = CACHE_FILE;
+
+ if((fd = open(cachename, O_RDONLY)) < 0)
+ DIE(("Unable to open cache %s\n", cachename));
+
+ if(fstat(fd,&statbuf) < 0)
+ DIE(("Unable to stat cache %s\n", cachename));
+
+ rules_ptr = mmap (NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if(rules_ptr == MAP_FAILED)
+ DIE (("Couldn't mmap file '%s', errno=%d: %s", cachename, errno, strerror (errno)));
+
+ header = (struct cache_header*) rules_ptr;
+ HAL_INFO(("preprobe: offset=%08lx, size=%d", header->fdi_rules_preprobe,
+ header->fdi_rules_information - header->fdi_rules_preprobe));
+ HAL_INFO(("information: offset=%08lx, size=%d", header->fdi_rules_information,
+ header->fdi_rules_policy - header->fdi_rules_information));
+ HAL_INFO(("policy: offset=%08lx, size=%d", header->fdi_rules_policy,
+ header->all_rules_size - header->fdi_rules_policy));
+
+ close(fd);
+}
+
+static void dir_mtime(const char * path, time_t * mt)
+{
+ struct dirent **namelist;
+ struct stat st;
+ int n;
+ char cpath[PATH_MAX];
+
+ if (!stat(path, &st)) {
+ if(st.st_mtime > *mt)
+ *mt = st.st_mtime;
+
+ if(S_ISDIR(st.st_mode)) {
+ n = scandir(path, &namelist, 0, alphasort);
+ if (n < 0)
+ return;
+ else {
+ while(n--) {
+#ifdef HAVE_SNPRINTF
+ snprintf(cpath, PATH_MAX, "%s/%s", path, namelist[n]->d_name);
+#else
+ sprintf(cpath, "%s/%s", path, namelist[n]->d_name);
+#endif
+ if(namelist[n]->d_name[0] != '.')
+ dir_mtime(cpath, mt);
+
+ free(namelist[n]);
+ }
+ free(namelist);
+ }
+ }
+ }
+}
+
+static void regen_cache(void)
+{
+ int ret;
+ struct stat st;
+ char cmd [PATH_MAX + 9];
+ char * c;
+
+ if((c = getenv("HALD_CACHE_BIN")) == NULL) {
+ c = HALD_CACHE_BIN;
+ }
+#ifdef HAVE_SNPRINTF
+ snprintf(cmd, PATH_MAX + 8, "%s --force", c);
+#else
+ sprintf(cmd, "%s --force", c);
+#endif
+
+ if(!stat(c, &st) && (ret = system(cmd)) !=- 1) {
+
+ if(WTERMSIG(ret) == SIGQUIT || WTERMSIG(ret) == SIGINT)
+ DIE(("Cache creation was interrupted"));
+
+ if(WEXITSTATUS(ret) == 0)
+ HAL_INFO(("Subprocess terminated normally, cache generated."));
+ }
+ else {
+ HAL_INFO(("Unable to generate cache"));
+ }
+}
+void cache_coherency_check(void)
+{
+ time_t mt;
+ struct stat st;
+ dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/preprobe", &mt);
+ dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/preprobe", &mt);
+ dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/information", &mt);
+ dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/information", &mt);
+ dir_mtime(PACKAGE_DATA_DIR "/hal/fdi/policy", &mt);
+ dir_mtime(PACKAGE_SYSCONF_DIR "/hal/fdi/policy", &mt);
+ if(!stat(CACHE_FILE, &st)) {
+ if(st.st_mtime < mt) {
+ HAL_INFO(("Cache needs update"));
+ regen_cache();
+ }
+ }
+ else
+ regen_cache();
+
+ HAL_INFO(("cache mtime is %d",mt));
+}
diff --git a/hald/mmap_cache.h b/hald/mmap_cache.h
new file mode 100644
index 0000000..5c136d5
--- /dev/null
+++ b/hald/mmap_cache.h
@@ -0,0 +1,37 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * mmap_cache.h : cache routine and macros declarations.
+ *
+ * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+
+#ifndef __MMAP_CACHE_H__
+
+void di_rules_init(void);
+void cache_coherency_check(void);
+
+#define RULES_PTR(x) ((void *)((unsigned char *) rules_ptr + x))
+#endif
diff --git a/hald/rule.h b/hald/rule.h
new file mode 100644
index 0000000..9c726d3
--- /dev/null
+++ b/hald/rule.h
@@ -0,0 +1,109 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * rule.h : struct rule and surrounding helpful declarations/macros.
+ *
+ * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2006 Kay Sievers, <kay.sievers at vrfy.org>
+ * Copyright (C) 2006 Richard Hughes <richard at hughsie.com>
+ * Copyright (C) 2007 Mikhail Kshevetskiy <mikhail.kshevetskiy at gmail.com>
+ * Copyright (C) 2007 Sergey Lapin <slapinid at gmail.com>
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef __RULE_H__
+#define __RULE__H__
+
+/* rule type to process */
+enum rule_type {
+ RULE_UNKNOWN,
+ RULE_MATCH,
+ RULE_MERGE,
+ RULE_APPEND,
+ RULE_PREPEND,
+ RULE_REMOVE,
+ RULE_CLEAR,
+ RULE_SPAWN,
+ RULE_EOF,
+};
+
+/* type of merge command */
+enum merge_type {
+ MERGE_UNKNOWN,
+ MERGE_STRING,
+ MERGE_BOOLEAN,
+ MERGE_INT32,
+ MERGE_UINT64,
+ MERGE_DOUBLE,
+ MERGE_COPY_PROPERTY,
+ MERGE_STRLIST,
+ MERGE_REMOVE,
+};
+
+/* type of match command */
+enum
+match_type {
+ MATCH_UNKNOWN,
+ MATCH_STRING,
+ MATCH_INT,
+ MATCH_UINT64,
+ MATCH_BOOL,
+ MATCH_EXISTS,
+ MATCH_EMPTY,
+ MATCH_ISASCII,
+ MATCH_IS_ABS_PATH,
+ MATCH_CONTAINS,
+ MATCH_CONTAINS_NCASE,
+ MATCH_PREFIX,
+ MATCH_PREFIX_NCASE,
+ MATCH_SUFFIX,
+ MATCH_SUFFIX_NCASE,
+ MATCH_COMPARE_LT,
+ MATCH_COMPARE_LE,
+ MATCH_COMPARE_GT,
+ MATCH_COMPARE_GE,
+};
+
+/* a "rule" structure that is a generic node of the fdi file */
+struct rule {
+ size_t rule_size; /* offset to next rule in the list (aligned to 4 bytes) */
+ u_int32_t jump_position; /* the rule to jumo position (aligned to 4 bytes) */
+
+ enum rule_type rtype; /* type of rule */
+ enum match_type type_match;
+ enum merge_type type_merge;
+
+ u_int32_t value_offset; /* offset to keys value (aligned to 4 bytes) */
+ size_t value_len; /* length of keys value */
+
+ size_t key_len;
+ char key[0];
+};
+
+struct cache_header {
+ u_int32_t fdi_rules_preprobe;
+ u_int32_t fdi_rules_information;
+ u_int32_t fdi_rules_policy;
+ u_int32_t all_rules_size;
+ char empty_string[4];
+};
+
+#define HAL_MAX_INDENT_DEPTH 64
+
+#endif
More information about the hal-commit
mailing list