summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2007-07-09 00:13:47 +0000
committernbd <nbd@3c298f89-4303-0410-b956-a3cf2f4a3e73>2007-07-09 00:13:47 +0000
commitaf7fc344c8cd92797809eebf8b41d49c350111b9 (patch)
tree767776b433698d58ab0604b5ce35ee9b1c719ada
parent88d097f618bae687424a3b7aeafeb078dc3143f0 (diff)
hotplug2 update - include hotplug2-init.rules from hotplug2.rules, fix permissions of various devices (fixes #2052)
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@7892 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--package/base-files/files/etc/hotplug2-init.rules22
-rw-r--r--package/hotplug2/Makefile2
-rw-r--r--package/hotplug2/files/hotplug2.rules18
-rw-r--r--package/hotplug2/patches/100-svn_update.patch1674
4 files changed, 1624 insertions, 92 deletions
diff --git a/package/base-files/files/etc/hotplug2-init.rules b/package/base-files/files/etc/hotplug2-init.rules
index 098ad047a..bcc4c6a9e 100644
--- a/package/base-files/files/etc/hotplug2-init.rules
+++ b/package/base-files/files/etc/hotplug2-init.rules
@@ -1,12 +1,34 @@
+
+DEVICENAME ~~ (null|full|ptmx|tty|zero) {
+ nothrottle
+ makedev /dev/%DEVICENAME% 0666
+ next
+}
+
DEVICENAME ~~ (tun|tap[0-9]) {
+ nothrottle
makedev /dev/net/%DEVICENAME% 0644
next
}
+DEVICENAME ~~ (ppp) {
+ nothrottle
+ makedev /dev/%DEVICENAME% 0600
+ next
+}
+
+DEVICENAME ~~ (controlC[0-9]|pcmC0D0*) {
+ nothrottle
+ makedev /dev/snd/%DEVICENAME% 0644
+ next
+}
+
DEVPATH is set {
+ nothrottle
makedev /dev/%DEVICENAME% 0644
}
+
SUBSYSTEM ~~ button {
exec kill -USR1 1 ;
}
diff --git a/package/hotplug2/Makefile b/package/hotplug2/Makefile
index ee35bd6fc..559732bf4 100644
--- a/package/hotplug2/Makefile
+++ b/package/hotplug2/Makefile
@@ -30,7 +30,7 @@ define Package/hotplug2/description
Hotplug2 is a trivial replacement of some of the UDev functionality
in a tiny pack, intended for Linux early userspace: Init RAM FS and InitRD.
endef
-MAKE_FLAGS += CFLAGS="$(TARGET_CFLAGS) -DHAVE_RULES"
+MAKE_FLAGS += CFLAGS="$(TARGET_CFLAGS) -DHAVE_RULES -I."
define Package/hotplug2/install
$(INSTALL_DIR) $(1)/etc
diff --git a/package/hotplug2/files/hotplug2.rules b/package/hotplug2/files/hotplug2.rules
index 3d7df41ef..a6697ae86 100644
--- a/package/hotplug2/files/hotplug2.rules
+++ b/package/hotplug2/files/hotplug2.rules
@@ -1,20 +1,4 @@
-DEVICENAME ~~ (tun|tap[0-9]) {
- nothrottle
- makedev /dev/net/%DEVICENAME% 0644
- next
-}
-
-DEVICENAME ~~ (controlC[0-9]|pcmC0D0*) {
- nothrottle
- makedev /dev/snd/%DEVICENAME% 0644
- next
-}
-
-DEVPATH is set {
- nothrottle
- makedev /dev/%DEVICENAME% 0644
-}
-
+$include /etc/hotplug2-init.rules
FIRMWARE is set {
nothrottle
exec /sbin/hotplug-call firmware;
diff --git a/package/hotplug2/patches/100-svn_update.patch b/package/hotplug2/patches/100-svn_update.patch
index 2844c6eb4..283e61371 100644
--- a/package/hotplug2/patches/100-svn_update.patch
+++ b/package/hotplug2/patches/100-svn_update.patch
@@ -1,4 +1,4 @@
-diff -urN -x.svn hotplug2-0.9/AUTHORS hotplug2/AUTHORS
+diff -urN -x .svn hotplug2-0.9/AUTHORS hotplug2/AUTHORS
--- hotplug2-0.9/AUTHORS 2006-10-08 18:13:50.000000000 +0200
+++ hotplug2/AUTHORS 2007-06-30 12:59:20.459674000 +0200
@@ -1,7 +1,11 @@
@@ -26,30 +26,41 @@ diff -urN -x.svn hotplug2-0.9/AUTHORS hotplug2/AUTHORS
-...anyone taking more than a short peek at the software.
\ No newline at end of file
+...anyone taking more than a short peek at the software.
-diff -urN -x.svn hotplug2-0.9/Changelog hotplug2/Changelog
+diff -urN -x .svn hotplug2-0.9/Changelog hotplug2/Changelog
--- hotplug2-0.9/Changelog 2006-10-08 15:32:31.000000000 +0200
-+++ hotplug2/Changelog 2007-06-28 14:51:00.009934640 +0200
-@@ -1,3 +1,10 @@
++++ hotplug2/Changelog 2007-07-09 01:17:14.865503750 +0200
+@@ -1,3 +1,13 @@
+0.9 - 1.0:
+* Add --set-rules-file.
+* Allow any ACTION.
+* Add 'printdebug' rule.
+* Fix chmod, chown, chgrp.
+* Use octal for chmod and makedev.
++* Add 'nothrottle' flag, allowing overriding max-children from a rule
++* Various bugfixes
++* Code comments
+
0.8 - 0.9:
* Use signals to handle children.
* Separate info and debugging output.
-@@ -44,4 +51,4 @@
+@@ -44,4 +54,4 @@
* Add more actions.
* Significant cleanup of rules handling.
* Better error reporting.
-
\ No newline at end of file
+
-diff -urN -x.svn hotplug2-0.9/common.mak hotplug2/common.mak
+diff -urN -x .svn hotplug2-0.9/common.mak hotplug2/common.mak
--- hotplug2-0.9/common.mak 2006-09-26 01:03:08.000000000 +0200
-+++ hotplug2/common.mak 2007-06-28 14:54:56.013056712 +0200
++++ hotplug2/common.mak 2007-07-09 01:17:14.869504000 +0200
+@@ -1,6 +1,6 @@
+ # vim:set sw=8 nosta:
+
+-CFLAGS=-Os -DHAVE_RULES -Wall -g
++CFLAGS=-Os -DHAVE_RULES -Wall -g -Wextra
+ LDFLAGS=-g
+
+ INSTALL=install -c -m 644
@@ -10,7 +10,7 @@
.PHONY: all clean dep install install-recursive clean-recursive \
dep-recursive all-recursive
@@ -59,7 +70,7 @@ diff -urN -x.svn hotplug2-0.9/common.mak hotplug2/common.mak
dep: dep-recursive
$(MAKEDEP)
.depend:
-diff -urN -x.svn hotplug2-0.9/docs/hotplug2.8 hotplug2/docs/hotplug2.8
+diff -urN -x .svn hotplug2-0.9/docs/hotplug2.8 hotplug2/docs/hotplug2.8
--- hotplug2-0.9/docs/hotplug2.8 2006-09-26 09:23:36.000000000 +0200
+++ hotplug2/docs/hotplug2.8 2007-06-28 14:50:59.874955160 +0200
@@ -22,6 +22,8 @@
@@ -80,7 +91,7 @@ diff -urN -x.svn hotplug2-0.9/docs/hotplug2.8 hotplug2/docs/hotplug2.8
.SH "SIGNALS"
.TP
\fBSIGUSR1\fR
-diff -urN -x.svn hotplug2-0.9/docs/hotplug2.rules.doc hotplug2/docs/hotplug2.rules.doc
+diff -urN -x .svn hotplug2-0.9/docs/hotplug2.rules.doc hotplug2/docs/hotplug2.rules.doc
--- hotplug2-0.9/docs/hotplug2.rules.doc 2006-09-26 10:19:46.000000000 +0200
+++ hotplug2/docs/hotplug2.rules.doc 2007-06-28 14:50:59.872955464 +0200
@@ -11,12 +11,12 @@
@@ -226,7 +237,7 @@ diff -urN -x.svn hotplug2-0.9/docs/hotplug2.rules.doc hotplug2/docs/hotplug2.rul
+ACTION == remove, PHYSDEVPATH ~~ "/usb[0-9]*/", DEVICENAME ~~ "^sd[a-z][0-9]+$", MAJOR is set, MINOR is set {
+ exec umount /mnt/%DEVICENAME%
+}
-diff -urN -x.svn hotplug2-0.9/docs/Makefile hotplug2/docs/Makefile
+diff -urN -x .svn hotplug2-0.9/docs/Makefile hotplug2/docs/Makefile
--- hotplug2-0.9/docs/Makefile 2006-09-26 00:27:02.000000000 +0200
+++ hotplug2/docs/Makefile 2007-06-28 14:50:59.875955008 +0200
@@ -2,12 +2,13 @@
@@ -245,7 +256,7 @@ diff -urN -x.svn hotplug2-0.9/docs/Makefile hotplug2/docs/Makefile
include ../common.mak
-diff -urN -x.svn hotplug2-0.9/examples/Makefile hotplug2/examples/Makefile
+diff -urN -x .svn hotplug2-0.9/examples/Makefile hotplug2/examples/Makefile
--- hotplug2-0.9/examples/Makefile 2006-09-26 01:03:08.000000000 +0200
+++ hotplug2/examples/Makefile 2007-06-28 14:50:59.991937376 +0200
@@ -2,19 +2,23 @@
@@ -280,10 +291,78 @@ diff -urN -x.svn hotplug2-0.9/examples/Makefile hotplug2/examples/Makefile
include ../common.mak
-diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
+diff -urN -x .svn hotplug2-0.9/filemap_utils.c hotplug2/filemap_utils.c
+--- hotplug2-0.9/filemap_utils.c 2006-09-25 12:14:12.000000000 +0200
++++ hotplug2/filemap_utils.c 2007-07-09 02:01:10.966249750 +0200
+@@ -16,7 +16,15 @@
+
+ #include "filemap_utils.h"
+
+-int map_file(char *filename, struct filemap_t *filemap) {
++/**
++ * Basic open/mmap wrapper to make things simpler.
++ *
++ * @1 Filename of the mmaped file
++ * @2 Pointer to filemap structure
++ *
++ * Returns: 0 if success, 1 otherwise
++ */
++int map_file(const char *filename, struct filemap_t *filemap) {
+ struct stat statbuf;
+
+ filemap->fd = open(filename, O_RDONLY);
+@@ -40,9 +48,16 @@
+ return 0;
+ }
+
++/**
++ * Basic close/munmap wrapper.
++ *
++ * @1 Pointer to filemap structure
++ *
++ * Returns: always 0
++ */
+ int unmap_file(struct filemap_t *filemap) {
+- close(filemap->fd);
+ munmap(filemap->map, filemap->size);
++ close(filemap->fd);
+
+ return 0;
+ }
+diff -urN -x .svn hotplug2-0.9/filemap_utils.h hotplug2/filemap_utils.h
+--- hotplug2-0.9/filemap_utils.h 2006-09-25 22:24:36.000000000 +0200
++++ hotplug2/filemap_utils.h 2007-07-09 02:01:10.962249500 +0200
+@@ -14,6 +14,6 @@
+ void *map;
+ };
+
+-int map_file(char *, struct filemap_t *);
++int map_file(const char *, struct filemap_t *);
+ int unmap_file(struct filemap_t *);
+ #endif
+diff -urN -x .svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
--- hotplug2-0.9/hotplug2.c 2006-10-08 15:18:23.000000000 +0200
-+++ hotplug2/hotplug2.c 2007-06-30 12:59:20.459674000 +0200
-@@ -36,6 +36,7 @@
++++ hotplug2/hotplug2.c 2007-07-09 02:01:10.962249500 +0200
+@@ -23,7 +23,9 @@
+ #include <linux/netlink.h>
+
+ #include "mem_utils.h"
++#include "filemap_utils.h"
+ #include "hotplug2.h"
++#include "hotplug2_utils.h"
+ #include "rules.h"
+ #include "childlist.h"
+
+@@ -32,10 +34,16 @@
+ child == NULL && \
+ highest_seqnum == get_kernel_seqnum())
+
++/*
++ * These variables are accessed from throughout the code.
++ *
++ * TODO: Move this into a hotplug2_t-like variable.
++ */
+ event_seqnum_t highest_seqnum = 0;
pid_t coldplug_p;
int coldplug = 1;
int persistent = 0;
@@ -291,11 +370,236 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
int max_child_c = 20;
int dumb = 0;
int terminate = 0;
-@@ -324,6 +325,41 @@
+@@ -45,6 +53,14 @@
+
+ char *modprobe_command = NULL;
+
++/**
++ * Release all memory associated with an uevent read from kernel. The given
++ * pointer is no longer valid, as it gets freed as well.
++ *
++ * @1 The event that is to be freed.
++ *
++ * Returns: void
++ */
+ inline void free_hotplug2_event(struct hotplug2_event_t *event) {
+ int i;
+
+@@ -57,6 +73,13 @@
+ free(event);
+ }
+
++/**
++ * A trivial function determining the action that the uevent.
++ *
++ * @1 String containing the action name (null-terminated).
++ *
++ * Returns: Macro of the given action
++ */
+ inline int get_hotplug2_event_action(char *action) {
+ if (!strcmp(action, "add"))
+ return ACTION_ADD;
+@@ -67,6 +90,14 @@
+ return ACTION_UNKNOWN;
+ }
+
++/**
++ * Looks up a value according to the given key.
++ *
++ * @1 A hotplug event structure
++ * @2 Key for lookup
++ *
++ * Returns: The value of the key or NULL if no such key found
++ */
+ char *get_hotplug2_value_by_key(struct hotplug2_event_t *event, char *key) {
+ int i;
+
+@@ -78,7 +109,16 @@
+ return NULL;
+ }
+
+-inline int add_hotplug2_event_env(struct hotplug2_event_t *event, char *item) {
++/**
++ * Appends a key-value pair described by the second argument to the
++ * hotplug event.
++ *
++ * @1 A hotplug event structure
++ * @1 An item in format "key=value" to be appended
++ *
++ * Returns: 0 if success, -1 if the string is malformed
++ */
++int add_hotplug2_event_env(struct hotplug2_event_t *event, char *item) {
+ char *ptr, *tmp;
+
+ ptr = strchr(item, '=');
+@@ -94,6 +134,8 @@
+
+ /*
+ * Variables not generated by kernel but demanded nonetheless...
++ *
++ * TODO: Split this to a different function
+ */
+ if (!strcmp(item, "DEVPATH")) {
+ event->env_vars_c++;
+@@ -109,6 +151,15 @@
+ return 0;
+ }
+
++/**
++ * Duplicates all allocated memory of a source hotplug event
++ * and returns a new hotplug event, an identical copy of the
++ * source event.
++ *
++ * @1 Source hotplug event structure
++ *
++ * Returns: A copy of the source event structure
++ */
+ inline struct hotplug2_event_t *dup_hotplug2_event(struct hotplug2_event_t *src) {
+ struct hotplug2_event_t *dest;
+ int i;
+@@ -129,6 +180,14 @@
+ return dest;
+ }
+
++/**
++ * Parses a string into a hotplug event structurs.
++ *
++ * @1 The event string (not null terminated)
++ * @2 The size of the event string
++ *
++ * Returns: A new event structure
++ */
+ inline struct hotplug2_event_t *get_hotplug2_event(char *event_str, int size) {
+ char *ptr;
+ struct hotplug2_event_t *event;
+@@ -161,59 +220,15 @@
+ return event;
+ }
+
+-inline event_seqnum_t get_kernel_seqnum() {
+- FILE *fp;
+-
+- char filename[64];
+- char seqnum[64];
+-
+- strcpy(filename, sysfs_seqnum_path);
+-
+- fp = fopen(filename, "r");
+- if (fp == NULL)
+- return 0;
+-
+- fread(seqnum, 1, 64, fp);
+- fclose(fp);
+-
+- return strtoull(seqnum, NULL, 0);
+-}
+-
+-inline int init_netlink_socket() {
+- int netlink_socket;
+- struct sockaddr_nl snl;
+- int buffersize = 16 * 1024 * 1024;
+-
+- memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+- snl.nl_family = AF_NETLINK;
+- snl.nl_pid = getpid();
+- snl.nl_groups = 1;
+- netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+- if (netlink_socket == -1) {
+- ERROR("opening netlink","Failed socket: %s.", strerror(errno));
+- return -1;
+- }
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
+-
+- /* Somewhat safe default. */
+- buffersize = 106496;
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
+- }
+- }
+-
+- if (bind(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
+- ERROR("opening netlink","Failed bind: %s.", strerror(errno));
+- close(netlink_socket);
+- return -1;
+- }
+-
+- return netlink_socket;
+-}
+-
++/**
++ * Evaluates an argument into a true/false value.
++ *
++ * @1 argument
++ * @2 argument flag
++ * @3 pointer to output value
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_bool_opt(char *argv, char *name, int *value) {
+ int rv = -1;
+
+@@ -238,7 +253,13 @@
+ }
+ }
+
+-void cleanup(void) {
++/**
++ * Performs a cleanup; closes uevent socket, resets signal
++ * handlers, waits for all the children.
++ *
++ * Returns: void
++ */
++void cleanup() {
+ pid_t p;
+
+ close(netlink_socket);
+@@ -254,6 +275,13 @@
+ INFO("cleanup", "All children terminated.");
+ }
+
++/**
++ * Handles all signals.
++ *
++ * @1 Signal identifier
++ *
++ * Returns: void
++ */
+ void sighandler(int sig) {
+ pid_t p;
+
+@@ -313,6 +341,14 @@
+ }
+
+ #ifdef HAVE_RULES
++/**
++ * Execute all rules for this particular event.
++ *
++ * @1 Hotplug event structure
++ * @2 Rules structure, containing array of rules
++ *
++ * Returns: void
++ */
+ void perform_action(struct hotplug2_event_t *event, struct rules_t *rules) {
+ int i, rv;
+
+@@ -324,13 +360,72 @@
free_hotplug2_event(event);
}
+
++/**
++ * Iterates through all rules, and performs an AND between all flags that
++ * would apply during execution (ie. all rules that have conditions matching
++ * the hotplug event).
++ *
++ * @1 Hotplug event structure
++ * @2 Rules structure, containing array of rules
++ *
++ * Returns: Flags that apply to all matching rules
++ */
+int flags_eval(struct hotplug2_event_t *event, struct rules_t *rules) {
+ int flags = FLAG_ALL;
+ int match = 0;
@@ -316,7 +620,7 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
+ * those we're adding.
+ */
+ if (match) {
-+ rule_flags(event, &rules->rules[i]);
++ rule_flags(&rules->rules[i]);
+ flags &= rules->rules[i].flags;
+ }
+ }
@@ -332,18 +636,54 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
+#define perform_action(event, rules)
#endif
++/**
++ * Blindly modprobe the modalias, nothing more.
++ *
++ * @1 Hotplug event structure
++ * @2 Modalias to be loaded
++ *
++ * Returns: void
++ */
void perform_dumb_action(struct hotplug2_event_t *event, char *modalias) {
-@@ -390,7 +426,9 @@
+ free_hotplug2_event(event);
+ execl(modprobe_command, modprobe_command, "-q", modalias, NULL);
+ }
+
++/**
++ * Attempt to figure out whether our modprobe command can handle modalias.
++ * If not, use our own wrapper.
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_modprobe_command() {
+ pid_t p;
+ int fds[2];
+@@ -381,6 +476,9 @@
+ }
+
+ int main(int argc, char *argv[]) {
++ /*
++ * TODO, cleanup
++ */
+ static char buffer[UEVENT_BUFFER_SIZE+512];
+ struct hotplug2_event_t *tmpevent;
+ char *modalias, *seqnum;
+@@ -390,28 +488,39 @@
int size;
int rv = 0;
int i;
-+ int flags;
++ unsigned int flags;
char *coldplug_command = NULL;
+ char *rules_file = HOTPLUG2_RULE_PATH;
sigset_t block_mask;
struct rules_t *rules = NULL;
-@@ -402,6 +440,7 @@
+- struct stat statbuf;
+- void *filemap;
+- int rule_fd;
++ struct filemap_t filemap;
+
+ struct options_t bool_options[] = {
{"persistent", &persistent},
{"coldplug", &coldplug},
{"udevtrigger", &coldplug}, /* compatibility */
@@ -351,7 +691,27 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
#ifdef HAVE_RULES
{"dumb", &dumb},
#endif
-@@ -435,15 +474,31 @@
+ {NULL, NULL}
+ };
+
++ /*
++ * We parse all the options...
++ */
+ for (argc--; argc > 0; argc--) {
+ argv++;
++ /*
++ * TODO, cleanup
++ */
+ for (i = 0; bool_options[i].name != NULL; i++) {
+ if (!get_bool_opt(*argv, bool_options[i].name, bool_options[i].value)) {
++ /*
++ * Bool options are --option or --no-options. If we handled
++ * it, quit iterating.
++ */
+ break;
+ } else {
+ if (!strcmp(*argv, "--max-children")) {
+@@ -435,52 +544,52 @@
break;
modprobe_command = *argv;
@@ -379,14 +739,44 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
+ * faillback to dumb mode.
+ */
if (!dumb) {
- filemap = MAP_FAILED;
+- filemap = MAP_FAILED;
- rule_fd = open(HOTPLUG2_RULE_PATH, O_RDONLY | O_NOATIME);
-+ rule_fd = open(rules_file, O_RDONLY | O_NOATIME);
- if (rule_fd == -1) {
+- if (rule_fd == -1) {
+- dumb = 1;
+- ERROR("rules parse","Unable to open rules file: %s.", strerror(errno));
+- goto end_rules;
+- }
+-
+- if (fstat(rule_fd, &statbuf)) {
+- dumb = 1;
+- ERROR("rules parse","Unable to stat rules file: %s.", strerror(errno));
+- goto end_rules;
+- }
+-
+- filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, rule_fd, 0);
+- if (filemap == MAP_FAILED) {
++ if (map_file(rules_file, &filemap)) {
++ ERROR("rules parse","Unable to open/mmap rules file.");
+ dumb = 1;
+- ERROR("rules parse","Unable to mmap rules file: %s.", strerror(errno));
+ goto end_rules;
+ }
+
+- rules = rules_from_config((char*)filemap);
++ rules = rules_from_config((char*)(filemap.map), NULL);
+ if (rules == NULL) {
+ ERROR("rules parse","Unable to parse rules file.");
dumb = 1;
- ERROR("rules parse","Unable to open rules file: %s.", strerror(errno));
-@@ -477,10 +532,12 @@
+ }
++
++ unmap_file(&filemap);
+ end_rules:
+- if (filemap != MAP_FAILED)
+- munmap(filemap, statbuf.st_size);
+- if (rule_fd != -1)
+- close(rule_fd);
+-
if (dumb == 1)
ERROR("rules parse","Parsing rules failed, switching to dumb mode.");
- } else if (!modprobe_command)
@@ -401,23 +791,83 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
{
if (get_modprobe_command()) {
ERROR("modprobe_command","Unable to autodetect modprobe command.");
-@@ -536,7 +593,7 @@
+@@ -489,7 +598,10 @@
+ DBG("modprobe_command", "Using modprobe: `%s'.", modprobe_command);
+ }
+
+- netlink_socket = init_netlink_socket();
++ /*
++ * Open netlink socket to read the uevents
++ */
++ netlink_socket = init_netlink_socket(NETLINK_BIND);
+
+ if (netlink_socket == -1) {
+ ERROR("netlink init","Unable to open netlink socket.");
+@@ -503,6 +615,9 @@
+ signal(SIGINT, sighandler);
+ signal(SIGCHLD, sighandler);
+
++ /*
++ * If we desire coldplugging, we initiate it right now.
++ */
+ if (coldplug) {
+ if (coldplug_command == NULL)
+ coldplug_command = UDEVTRIGGER_COMMAND;
+@@ -523,10 +638,19 @@
+ coldplug_p = FORK_FINISHED;
+ }
+
++ /*
++ * Main loop reading uevents
++ */
+ while (!terminate) {
++ /*
++ * Read the uevent packet
++ */
+ size = recv(netlink_socket, &buffer, sizeof(buffer), 0);
+ recv_errno = errno;
+
++ /*
++ * Parse the event into an event structure
++ */
+ tmpevent = get_hotplug2_event(buffer, size);
+ if (tmpevent == NULL) {
+@@ -534,26 +658,61 @@
+ continue;
+ }
+
++ /*
++ * Look up two important items of the event
++ */
modalias = get_hotplug2_value_by_key(tmpevent, "MODALIAS");
seqnum = get_hotplug2_value_by_key(tmpevent, "SEQNUM");
-
+
++ /*
++ * Seqnum is necessary not to end up in a race with the kernel.
++ */
if (seqnum == NULL) {
free_hotplug2_event(tmpevent);
ERROR("reading events", "Malformed event read (missing SEQNUM).");
-@@ -547,13 +604,35 @@
+ continue;
+ }
+
++ /*
++ * Maintain seqnum continuity
++ */
+ cur_seqnum = strtoull(seqnum, NULL, 0);
if (cur_seqnum > highest_seqnum)
highest_seqnum = cur_seqnum;
- if (tmpevent->action == ACTION_ADD && (!dumb || modalias != NULL)) {
++ /*
++ * If we are in smart mode, we'll always pass. If we're in dumb mode,
++ * we only pass events that have 'add' action and have modalias set.
++ */
+ if ((dumb && tmpevent->action == ACTION_ADD && modalias != NULL) || (!dumb)) {
+ /*
-+ * Pre-evaluation
++ * Pre-evaluation of the flags
+ */
+ if (!dumb && override) {
+ flags = flags_eval(tmpevent, rules);
@@ -449,7 +899,7 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
}
sigemptyset(&block_mask);
-@@ -562,17 +641,15 @@
+@@ -562,17 +721,18 @@
p = fork();
switch (p) {
case -1:
@@ -457,6 +907,9 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
+ ERROR("event", "fork failed: %s.", strerror(errno));
break;
case 0:
++ /*
++ * TODO: We do not have to dup here, or do we?
++ */
sigprocmask(SIG_UNBLOCK, &block_mask, 0);
signal(SIGCHLD, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
@@ -468,7 +921,7 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
perform_dumb_action(dup_hotplug2_event(tmpevent), modalias);
exit(0);
break;
-@@ -593,12 +670,10 @@
+@@ -593,12 +753,10 @@
signal(SIGINT, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
@@ -481,26 +934,596 @@ diff -urN -x.svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
cleanup();
-diff -urN -x.svn hotplug2-0.9/linux24_compat/hotplug2-modwrap.c hotplug2/linux24_compat/hotplug2-modwrap.c
+diff -urN -x .svn hotplug2-0.9/hotplug2-dnode.c hotplug2/hotplug2-dnode.c
+--- hotplug2-0.9/hotplug2-dnode.c 2006-09-26 17:35:35.000000000 +0200
++++ hotplug2/hotplug2-dnode.c 2007-07-09 01:17:14.869504000 +0200
+@@ -27,6 +27,7 @@
+
+ #include "mem_utils.h"
+ #include "hotplug2.h"
++#include "hotplug2_utils.h"
+ #include "parser_utils.h"
+
+ #define MODALIAS_MAX_LEN 1024
+@@ -45,59 +46,17 @@
+
+ #define TEST_INPUT_BIT(i,bm) (bm[i / BITS_PER_LONG] & (((unsigned long)1) << (i%BITS_PER_LONG)))
+
+-int init_netlink_socket() {
+- int netlink_socket;
+- struct sockaddr_nl snl;
+- int buffersize = 16 * 1024 * 1024;
+-
+- memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+- snl.nl_family = AF_NETLINK;
+- snl.nl_pid = getpid();
+- snl.nl_groups = 1;
+- netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+- if (netlink_socket == -1) {
+- ERROR("opening netlink","Failed socket: %s.", strerror(errno));
+- return -1;
+- }
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUFFORCE, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
+-
+- /* Somewhat safe default. */
+- buffersize = 106496;
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUF, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
+- }
+- }
+-
+- if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
+- ERROR("opening netlink","Failed bind: %s.", strerror(errno));
+- close(netlink_socket);
+- return -1;
+- }
+-
+- return netlink_socket;
+-}
+-
+-inline event_seqnum_t get_kernel_seqnum() {
+- FILE *fp;
+-
+- char filename[64];
+- char seqnum[64];
+-
+- strcpy(filename, sysfs_seqnum_path);
+-
+- fp = fopen(filename, "r");
+- if (fp == NULL)
+- return 0;
+-
+- fread(seqnum, 1, 64, fp);
+- fclose(fp);
+-
+- return strtoull(seqnum, NULL, 0);
+-}
+-
++/**
++ * Parses a bitmap; output is a list of offsets of bits of a bitmap
++ * of arbitrary size that are set to 1.
++ *
++ * @1 Name of the bitmap parsed
++ * @2 The actual bitmap pointer
++ * @3 Lower boundary of the bitmap
++ * @4 Upper boundary of the bitmap
++ *
++ * Returns: Newly allocated string containing the offsets
++ */
+ char *bitmap_to_bitstring(char name, unsigned long *bm, unsigned int min_bit, unsigned int max_bit)
+ {
+ char *rv;
+@@ -120,6 +79,15 @@
+ return rv;
+ }
+
++/**
++ * Reverses the bitmap_to_bitstring function.
++ *
++ * @1 Bitstring to be converted
++ * @2 Output bitmap
++ * @3 Size of the whole bitmap
++ *
++ * Returns: void
++ */
+ void string_to_bitmap(char *input, unsigned long *bitmap, int bm_len) {
+ char *token, *ptr;
+ int i = 0;
+@@ -146,6 +114,14 @@
+ } \
+ bitmap = bitmap_to_bitstring(name, bitmap ## _bits, min, mapkey ## _MAX);
+
++/**
++ * Creates an input modalias out of preset environmental variables.
++ *
++ * @1 Pointer to where modalias will be created
++ * @2 Maximum size of the modalias
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_input_modalias(char *modalias, int modalias_len) {
+ char *product_env;
+ char *ptr;
+@@ -245,6 +221,14 @@
+ #undef NBITS
+ #undef TEST_INPUT_BIT
+
++/**
++ * Creates a PCI modalias out of preset environmental variables.
++ *
++ * @1 Pointer to where modalias will be created
++ * @2 Maximum size of the modalias
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_pci_modalias(char *modalias, int modalias_len) {
+ char *class_env, *id_env, *subsys_env;
+ char *ptr;
+@@ -290,6 +274,15 @@
+ return 0;
+ }
+
++/**
++ * Creates an IEEE1394 (FireWire) modalias out of preset environmental
++ * variables.
++ *
++ * @1 Pointer to where modalias will be created
++ * @2 Maximum size of the modalias
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_ieee1394_modalias(char *modalias, int modalias_len) {
+ char *vendor_env, *model_env;
+ char *specifier_env, *version_env;
+@@ -317,6 +310,14 @@
+ return 0;
+ }
+
++/**
++ * Creates a serio modalias out of preset environmental variables.
++ *
++ * @1 Pointer to where modalias will be created
++ * @2 Maximum size of the modalias
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_serio_modalias(char *modalias, int modalias_len) {
+ char *serio_type_env, *serio_proto_env;
+ char *serio_id_env, *serio_extra_env;
+@@ -344,6 +345,14 @@
+ return 0;
+ }
+
++/**
++ * Creates an USB modalias out of preset environmental variables.
++ *
++ * @1 Pointer to where modalias will be created
++ * @2 Maximum size of the modalias
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
+ int get_usb_modalias(char *modalias, int modalias_len) {
+ char *product_env, *type_env, *interface_env;
+ char *ptr;
+@@ -409,6 +418,16 @@
+ return 0;
+ }
+
++/**
++ * Distributes modalias generating according to the bus name.
++ *
++ * @1 Bus name
++ * @2 Pointer to where modalias will be created
++ * @3 Maximum size of the modalias
++ *
++ * Returns: The return value of the subsystem modalias function, or -1 if
++ * no match.
++ */
+ int get_modalias(char *bus, char *modalias, int modalias_len) {
+ memset(modalias, 0, modalias_len);
+
+@@ -435,6 +454,16 @@
+ return -1;
+ }
+
++/**
++ * Turns all environmental variables as set when invoked by /proc/sys/hotplug
++ * into an uevent formatted (thus not null-terminated) string.
++ *
++ * @1 All environmental variables
++ * @2 Bus of the event (as read from argv)
++ * @3 Pointer to size of the returned uevent string
++ *
++ * Returns: Not null terminated uevent string.
++ */
+ inline char *get_uevent_string(char **environ, char *bus, unsigned long *uevent_string_len) {
+ char *uevent_string;
+ char *tmp;
+@@ -516,7 +545,7 @@
+ return 1;
+ }
+
+- netlink_socket = init_netlink_socket();
++ netlink_socket = init_netlink_socket(NETLINK_CONNECT);
+ if (netlink_socket == -1) {
+ ERROR("netlink init","Unable to open netlink socket.");
+ goto exit;
+diff -urN -x .svn hotplug2-0.9/hotplug2.h hotplug2/hotplug2.h
+--- hotplug2-0.9/hotplug2.h 2006-10-08 12:21:56.000000000 +0200
++++ hotplug2/hotplug2.h 2007-07-09 01:17:14.865503750 +0200
+@@ -34,7 +34,7 @@
+ #endif
+
+ #ifndef O_NOATIME
+-#define O_NOATIME 01000000
++#define O_NOATIME 01000000
+ #endif
+
+ #define ERROR(action, fmt, arg...) fprintf(stderr, "[%s]: " fmt"\n", action, ##arg);
+@@ -47,7 +47,7 @@
+
+ #define UEVENT_BUFFER_SIZE 2048
+ #define HOTPLUG2_POLL_INTERVAL 20000
+-#define HOTPLUG2_THROTTLE_INTERVAL 10000
++#define HOTPLUG2_THROTTLE_INTERVAL 10000
+ #define HOTPLUG2_RULE_PATH "/etc/hotplug2.rules"
+
+ #define ACTION_ADD 0
+diff -urN -x .svn hotplug2-0.9/hotplug2_utils.c hotplug2/hotplug2_utils.c
+--- hotplug2-0.9/hotplug2_utils.c 1970-01-01 01:00:00.000000000 +0100
++++ hotplug2/hotplug2_utils.c 2007-07-09 01:17:14.869504000 +0200
+@@ -0,0 +1,96 @@
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <fcntl.h>
++#include <stdio.h>
++#include <unistd.h>
++#include <errno.h>
++#include <sys/socket.h>
++#include <sys/types.h>
++#include <sys/un.h>
++#include <sys/wait.h>
++#include <linux/types.h>
++#include <linux/netlink.h>
++
++#include "hotplug2_utils.h"
++
++/**
++ * A trivial function that reads kernel seqnum from sysfs.
++ *
++ * Returns: Seqnum as read from sysfs
++ */
++inline event_seqnum_t get_kernel_seqnum() {
++ FILE *fp;
++
++ char filename[64];
++ char seqnum[64];
++
++ strcpy(filename, sysfs_seqnum_path);
++
++ fp = fopen(filename, "r");
++ if (fp == NULL)
++ return 0;
++
++ fread(seqnum, 1, 64, fp);
++ fclose(fp);
++
++ return strtoull(seqnum, NULL, 0);
++}
++
++/**
++ * Opens a PF_NETLINK socket into the kernel, to read uevents.
++ *
++ * @1 Specifies type of socket (whether we bind or whether we connect)
++ *
++ * Returns: Socket fd if succesful, -1 otherwise.
++ */
++inline int init_netlink_socket(int type) {
++ int netlink_socket;
++ struct sockaddr_nl snl;
++ int buffersize = 16 * 1024 * 1024;
++
++ memset(&snl, 0x00, sizeof(struct sockaddr_nl));
++ snl.nl_family = AF_NETLINK;
++ snl.nl_pid = getpid();
++ snl.nl_groups = 1;
++ netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
++ if (netlink_socket == -1) {
++ ERROR("opening netlink","Failed socket: %s.", strerror(errno));
++ return -1;
++ }
++
++ /*
++ * We're trying to override buffer size. If we fail, we attempt to set a big buffer and pray.
++ */
++ if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize))) {
++ ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
++
++ /* Somewhat safe default. */
++ buffersize = 106496;
++
++ if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize))) {
++ ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
++ }
++ }
++
++ /*
++ * hotplug2-dnode performs connect, while hotplug2 daemon binds
++ */
++ switch (type) {
++ case NETLINK_CONNECT:
++ if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
++ ERROR("opening netlink","Failed connect: %s.", strerror(errno));
++ close(netlink_socket);
++ return -1;
++ }
++
++ default:
++ if (bind(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
++ ERROR("opening netlink","Failed bind: %s.", strerror(errno));
++ close(netlink_socket);
++ return -1;
++ }
++ }
++
++ return netlink_socket;
++}
+diff -urN -x .svn hotplug2-0.9/hotplug2_utils.h hotplug2/hotplug2_utils.h
+--- hotplug2-0.9/hotplug2_utils.h 1970-01-01 01:00:00.000000000 +0100
++++ hotplug2/hotplug2_utils.h 2007-07-09 01:17:14.869504000 +0200
+@@ -0,0 +1,21 @@
++/*****************************************************************************\
++* _ _ _ _ ___ *
++* | || | ___ | |_ _ __ | | _ _ __ _ |_ ) *
++* | __ |/ _ \| _|| '_ \| || || |/ _` | / / *
++* |_||_|\___/ \__|| .__/|_| \_,_|\__, |/___| *
++* |_| |___/ *
++\*****************************************************************************/
++
++#ifndef HOTPLUG2_UTILS_H
++#define HOTPLUG2_UTILS_H 1
++
++#include "hotplug2.h"
++
++#define NETLINK_UNDEFINED 0
++#define NETLINK_CONNECT 1
++#define NETLINK_BIND 2
++
++inline event_seqnum_t get_kernel_seqnum();
++inline int init_netlink_socket(int);
++
++#endif
+diff -urN -x .svn hotplug2-0.9/linux24_compat/hotplug2-coldplug-2.4.c hotplug2/linux24_compat/hotplug2-coldplug-2.4.c
+--- hotplug2-0.9/linux24_compat/hotplug2-coldplug-2.4.c 2006-09-25 22:22:47.000000000 +0200
++++ hotplug2/linux24_compat/hotplug2-coldplug-2.4.c 2007-07-09 01:17:14.793499250 +0200
+@@ -28,59 +28,7 @@
+ #include "../mem_utils.h"
+ #include "../parser_utils.h"
+ #include "../filemap_utils.h"
+-
+-inline int init_netlink_socket() {
+- int netlink_socket;
+- struct sockaddr_nl snl;
+- int buffersize = 16 * 1024 * 1024;
+-
+- memset(&snl, 0x00, sizeof(struct sockaddr_nl));
+- snl.nl_family = AF_NETLINK;
+- snl.nl_pid = getpid();
+- snl.nl_groups = 1;
+- netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+- if (netlink_socket == -1) {
+- ERROR("opening netlink","Failed socket: %s.", strerror(errno));
+- return -1;
+- }
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUFFORCE, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
+-
+- /* Somewhat safe default. */
+- buffersize = 106496;
+-
+- if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUF, &buffersize, sizeof(buffersize))) {
+- ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
+- }
+- }
+-
+- if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
+- ERROR("opening netlink","Failed bind: %s.", strerror(errno));
+- close(netlink_socket);
+- return -1;
+- }
+-
+- return netlink_socket;
+-}
+-
+-inline event_seqnum_t get_kernel_seqnum() {
+- FILE *fp;
+-
+- char filename[64];
+- char seqnum[64];
+-
+- strcpy(filename, sysfs_seqnum_path);
+-
+- fp = fopen(filename, "r");
+- if (fp == NULL)
+- return 0;
+-
+- fread(seqnum, 1, 64, fp);
+- fclose(fp);
+-
+- return strtoull(seqnum, NULL, 0);
+-}
++#include "../hotplug2_utils.h"
+
+ inline char *get_uevent_string(char **environ, unsigned long *uevent_string_len) {
+ char *uevent_string;
+@@ -413,7 +361,7 @@
+ int main(int argc, char *argv[], char **environ) {
+ int netlink_socket;
+
+- netlink_socket = init_netlink_socket();
++ netlink_socket = init_netlink_socket(NETLINK_CONNECT);
+ if (netlink_socket == -1) {
+ ERROR("netlink init","Unable to open netlink socket.");
+ return 1;
+diff -urN -x .svn hotplug2-0.9/linux24_compat/hotplug2-modwrap.c hotplug2/linux24_compat/hotplug2-modwrap.c
--- hotplug2-0.9/linux24_compat/hotplug2-modwrap.c 2006-09-25 22:23:07.000000000 +0200
-+++ hotplug2/linux24_compat/hotplug2-modwrap.c 2007-06-28 14:50:59.926947256 +0200
-@@ -122,6 +122,12 @@
++++ hotplug2/linux24_compat/hotplug2-modwrap.c 2007-07-09 01:17:14.789499000 +0200
+@@ -30,8 +30,19 @@
+ #include "../parser_utils.h"
+ #include "../filemap_utils.h"
+
++#define MODULES_PATH "/lib/modules/"
++#define MODULES_ALIAS "modules.alias"
++
++/**
++ * A simple fork/exec wrapper
++ *
++ * @1 Complete argv, including app path
++ *
++ * Returns: -1 if error, children return value otherwise
++ */
+ int execute(char **argv) {
+ pid_t p;
++ int status;
+
+ p = fork();
+ switch (p) {
+@@ -42,10 +53,11 @@
+ exit(1);
+ break;
+ default:
+- waitpid(p, NULL, 0);
++ waitpid(p, &status, 0);
+ break;
+ }
+- return 0;
++
++ return WEXITSTATUS(status);
+ }
+
+ int main(int argc, char *argv[]) {
+@@ -63,21 +75,36 @@
+
+ match_alias = strdup(argv[argc - 1]);
+
++ /*
++ * If we can't do uname, we're absolutely screwed and there's no
++ * sense thinking twice about anything.
++ */
+ if (uname(&unamebuf)) {
+ ERROR("uname", "Unable to perform uname: %s.", strerror(errno));
+ return 1;
+ }
+
+- /* We use this one */
++ /*
++ * We allow setting the modprobe command to an arbitrary value.
++ *
++ * The whole trick lies in executing modprobe with exactly the
++ * same argv as this app was executed, except we use a different
++ * argv[0] (application path) and argv[argc-1] (we substitute
++ * the given modalias by the matching module name)
++ */
+ argv[0] = getenv("MODPROBE_COMMAND");
+ if (argv[0] == NULL)
+ argv[0] = "/sbin/modprobe";
+-
+- /* "/lib/modules/" + "/" + "\0" */
+- filename = xmalloc(15 + strlen(unamebuf.release) + strlen("modules.alias"));
+- strcpy(filename, "/lib/modules/");
++
++ /*
++ * Compose a path, /lib/modules/`uname -r`/modules.alias
++ *
++ * "/lib/modules/" + "/" + "\0"
++ */
++ filename = xmalloc(strlen(MODULES_PATH) + strlen(unamebuf.release) + strlen(MODULES_ALIAS));
++ strcpy(filename, MODULES_PATH);
+ strcat(filename, unamebuf.release);
+- strcat(filename, "/modules.alias");
++ strcat(filename, MODULES_ALIAS);
+
+ if (map_file(filename, &aliasmap)) {
+ ERROR("map_file", "Unable to map file: `%s'.", filename);
+@@ -86,10 +113,16 @@
+ return 1;
+ }
+
++ /*
++ * Read all the aliases, match them against given parameter.
++ */
+ nptr = aliasmap.map;
+ while ((line = dup_line(nptr, &nptr)) != NULL) {
+ nline = line;
+
++ /*
++ * We want aliases only
++ */
+ token = dup_token(nline, &nline, isspace);
+ if (!token || strcmp(token, "alias")) {
+ free(token);
+@@ -98,12 +131,18 @@
+ }
+ free(token);
+
++ /*
++ * It's an alias, so fetch it
++ */
+ cur_alias = dup_token(nline, &nline, isspace);
+ if (!cur_alias) {
+ free(line);
+ continue;
+ }
+
++ /*
++ * And now we get the module name
++ */
+ module = dup_token(nline, &nline, isspace);
+ if (!module) {
+ free(line);
+@@ -111,10 +150,14 @@
+ continue;
+ }
+
++ /*
++ * If we match, we do the modalias->module name
++ * substitution as described above and execute.
++ */
+ if (!fnmatch(cur_alias, match_alias, 0)) {
+ argv[argc - 1] = module;
+ if (execute(argv)) {
+- ERROR("execute", "Unable to execute: `%s'.", argv[0]);
++ ERROR("execute", "Error during exection of: `%s'.", argv[0]);
+ }
+ }
+
+@@ -122,6 +165,17 @@
free(module);
free(line);
}
+
++ /*
++ * Perhaps we didn't match anything, so we might've been given
++ * a module name instead of a modalias. Try to modprobe it
++ * right away.
++ */
+ if (strcmp(argv[argc - 1], match_alias) == 0) {
+ if (execute(argv)) {
-+ ERROR("execute", "Unable to execute: `%s'.", argv[0]);
++ ERROR("execute", "Error during exection of: `%s'.", argv[0]);
+ }
+ }
free(filename);
free(match_alias);
-diff -urN -x.svn hotplug2-0.9/linux24_compat/Makefile hotplug2/linux24_compat/Makefile
+diff -urN -x .svn hotplug2-0.9/linux24_compat/Makefile hotplug2/linux24_compat/Makefile
--- hotplug2-0.9/linux24_compat/Makefile 2006-09-26 00:26:46.000000000 +0200
-+++ hotplug2/linux24_compat/Makefile 2007-06-28 14:50:59.926947256 +0200
-@@ -2,13 +2,14 @@
++++ hotplug2/linux24_compat/Makefile 2007-07-09 01:17:14.793499250 +0200
+@@ -2,16 +2,17 @@
BINS=generate_alias hotplug2-coldplug-2.4 hotplug2-modwrap
SUBDIRS=
@@ -516,11 +1539,15 @@ diff -urN -x.svn hotplug2-0.9/linux24_compat/Makefile hotplug2/linux24_compat/Ma
+ $(INSTALL_BIN) generate_alias $(DESTDIR)/usr/sbin/
- hotplug2-coldplug-2.4: hotplug2-coldplug-2.4.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
-diff -urN -x.svn hotplug2-0.9/Makefile hotplug2/Makefile
+-hotplug2-coldplug-2.4: hotplug2-coldplug-2.4.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
++hotplug2-coldplug-2.4: hotplug2-coldplug-2.4.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o ../hotplug2_utils.o
+ hotplug2-modwrap: hotplug2-modwrap.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
+ generate_alias: generate_alias.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
+
+diff -urN -x .svn hotplug2-0.9/Makefile hotplug2/Makefile
--- hotplug2-0.9/Makefile 2006-09-26 01:03:08.000000000 +0200
-+++ hotplug2/Makefile 2007-06-28 14:51:00.014933880 +0200
-@@ -2,12 +2,13 @@
++++ hotplug2/Makefile 2007-07-09 01:17:14.869504000 +0200
+@@ -2,16 +2,17 @@
BINS=hotplug2 hotplug2-dnode
SUBDIRS=linux24_compat docs examples
@@ -534,14 +1561,132 @@ diff -urN -x.svn hotplug2-0.9/Makefile hotplug2/Makefile
+ $(INSTALL_BIN) $(BINS) $(DESTDIR)/sbin/
- hotplug2: hotplug2.o childlist.o mem_utils.o rules.o
-diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+-hotplug2: hotplug2.o childlist.o mem_utils.o rules.o
+-hotplug2-dnode: hotplug2-dnode.o mem_utils.o parser_utils.o
++hotplug2: hotplug2.o hotplug2_utils.o childlist.o mem_utils.o rules.o filemap_utils.o
++hotplug2-dnode: hotplug2-dnode.o hotplug2_utils.o mem_utils.o parser_utils.o
+
+
+ include common.mak
+diff -urN -x .svn hotplug2-0.9/mem_utils.c hotplug2/mem_utils.c
+--- hotplug2-0.9/mem_utils.c 2006-09-25 22:21:45.000000000 +0200
++++ hotplug2/mem_utils.c 2007-07-09 01:17:14.865503750 +0200
+@@ -9,6 +9,13 @@
+ #include <stdlib.h>
+ #include <stdio.h>
+
++/**
++ * A malloc wrapper. Exits if no memory.
++ *
++ * @1 Ammount of memory to allocate
++ *
++ * Returns: Pointer to freshly allocated memory
++ */
+ inline void *xmalloc(size_t size) {
+ void *ptr;
+ ptr = malloc(size);
+@@ -19,6 +26,14 @@
+ return ptr;
+ }
+
++/**
++ * A realloc wrapper. Exits if no memory.
++ *
++ * @1 Old pointer
++ * @2 Ammount of memory to allocate
++ *
++ * Returns: Pointer to reallocated memory
++ */
+ inline void *xrealloc(void *inptr, size_t size) {
+ void *ptr;
+ ptr = realloc(inptr, size);
+diff -urN -x .svn hotplug2-0.9/parser_utils.c hotplug2/parser_utils.c
+--- hotplug2-0.9/parser_utils.c 2006-09-25 22:21:13.000000000 +0200
++++ hotplug2/parser_utils.c 2007-07-09 01:17:14.865503750 +0200
+@@ -12,6 +12,16 @@
+ #include "mem_utils.h"
+ #include "parser_utils.h"
+
++/**
++ * Creates a newly allocated null-terminated string representing line
++ * starting at a given pointer and ending at the closest newline. If
++ * no newline present, returns NULL. TODO, use dup_token
++ *
++ * @1 Starting pointer
++ * @2 Pointer where the end position is returned
++ *
++ * Returns: Newly allocated string containing the line or NULL
++ */
+ char *dup_line(char *start, char **nptr) {
+ char *ptr, *rv;
+
+@@ -29,6 +39,15 @@
+ return rv;
+ }
+
++/**
++ * Returns a token delimited by the given function.
++ *
++ * @1 Starting pointer
++ * @2 Pointer where the end position is returned
++ * @3 Function that identifies the delimiter characters
++ *
++ * Returns: Newly allocated string containing the token or NULL
++ */
+ char *dup_token(char *start, char **nptr, int (*isdelimiter)(int)) {
+ char *ptr, *rv;
+
+@@ -56,6 +75,16 @@
+ return rv;
+ }
+
++/**
++ * Returns the last token delimited by the given function.
++ *
++ * @1 Starting pointer of the whole string
++ * @2 Starting position
++ * @3 Pointer where the end position is returned
++ * @4 Function that identifies the delimiter characters
++ *
++ * Returns: Newly allocated string containing the token or NULL
++ */
+ char *dup_token_r(char *start, char *start_string, char **nptr, int (*isdelimiter)(int)) {
+ char *ptr, *rv;
+
+diff -urN -x .svn hotplug2-0.9/rules.c hotplug2/rules.c
--- hotplug2-0.9/rules.c 2006-09-29 22:19:31.000000000 +0200
-+++ hotplug2/rules.c 2007-06-30 12:44:52.501430000 +0200
-@@ -59,6 +59,24 @@
++++ hotplug2/rules.c 2007-07-09 02:01:10.962249500 +0200
+@@ -22,11 +22,18 @@
+ #include <sys/stat.h>
+
+ #include "mem_utils.h"
++#include "filemap_utils.h"
+ #include "hotplug2.h"
+ #include "rules.h"
+
+-#define last_rule return_rules->rules[return_rules->rules_c - 1]
+
++/**
++ * Function supplementing 'mkdir -p'.
++ *
++ * @1 Path to be mkdir'd
++ *
++ * Returns: void
++ */
+ static void mkdir_p(char *path) {
+ char *ptr;
+ struct stat statbuf;
+@@ -59,6 +66,40 @@
free(path);
}
++/**
++ * Function supplementing 'rmdir -p'.
++ *
++ * @1 Path to be rmdir'd
++ *
++ * Returns: void
++ */
+static void rmdir_p(char *path) {
+ char *ptr;
+
@@ -560,23 +1705,156 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+ free(path);
+}
+
++/**
++ * Replaces all needles by a given value.
++ *
++ * @1 Haystack (which gets free'd in the function)
++ * @2 Needle
++ * @3 Needle replacement
++ *
++ * Returns: Newly allocated haysteck after replacement.
++ */
static char *replace_str(char *hay, char *needle, char *replacement) {
char *ptr, *start, *bptr, *buf;
int occurences, j;
-@@ -128,7 +146,7 @@
+@@ -128,7 +169,15 @@
return buf;
}
-inline int isescaped(char *hay, char *ptr) {
++/**
++ * Trivial utility, figuring out whether a character is escaped or not.
++ *
++ * @1 Haystack
++ * @2 Pointer to the character in question
++ *
++ * Returns: 1 if escaped, 0 otherwise
++ */
+static inline int isescaped(char *hay, char *ptr) {
if (ptr <= hay)
return 0;
-@@ -250,11 +268,30 @@
+@@ -138,6 +187,15 @@
+ return 1;
+ }
+
++/**
++ * Performs replacement of all keys by their value based on the hotplug
++ * event structure. Keys are identified as strings %KEY%.
++ *
++ * @1 Haystack
++ * @2 Hotplug event structure
++ *
++ * Returns: Newly allocated haystack (old is freed)
++ */
+ static char *replace_key_by_value(char *hay, struct hotplug2_event_t *event) {
+ char *sptr = hay, *ptr = hay;
+ char *buf, *replacement;
+@@ -171,6 +229,17 @@
+ return hay;
+ }
+
++/**
++ * Obtains all information from hotplug event structure about a device node.
++ * Creates the device node at a given path (expandable by keys) and with
++ * given mode.
++ *
++ * @1 Hotplug event structure
++ * @2 Path (may contain keys)
++ * @3 Mode of the file
++ *
++ * Returns: 0 if success, non-zero otherwise
++ */
+ static int make_dev_from_event(struct hotplug2_event_t *event, char *path, mode_t devmode) {
+ char *subsystem, *major, *minor, *devpath;
+ int rv = 1;
+@@ -196,12 +265,27 @@
+ path = replace_key_by_value(path, event);
+ mkdir_p(path);
+ rv = mknod(path, devmode, makedev(atoi(major), atoi(minor)));
++
++ /*
++ * Fixes an issue caused by devmode being modified by umask.
++ */
++ chmod(path, devmode);
++
+ free(path);
+
+ return_value:
+ return rv;
+ }
+
++/**
++ * Execute an application without invoking a shell.
++ *
++ * @1 Hotplug event structure
++ * @2 Path to the application, with expandable keys
++ * @3 Argv for the application, with expandable keys
++ *
++ * Returns: Exit status of the application.
++ */
+ static int exec_noshell(struct hotplug2_event_t *event, char *application, char **argv) {
+ pid_t p;
+ int i, status;
+@@ -211,11 +295,12 @@
+ case -1:
+ return -1;
+ case 0:
++ application = replace_key_by_value(strdup(application), event);
+ for (i = 0; argv[i] != NULL; i++) {
+ argv[i] = replace_key_by_value(argv[i], event);
+ }
+ execvp(application, argv);
+- exit(0);
++ exit(127);
+ break;
+ default:
+ if (waitpid(p, &status, 0) == -1)
+@@ -226,6 +311,14 @@
+ }
+ }
+
++/**
++ * Execute an application while invoking a shell.
++ *
++ * @1 Hotplug event structure
++ * @2 The application and all its arguments, with expandable keys
++ *
++ * Returns: Exit status of the application.
++ */
+ static int exec_shell(struct hotplug2_event_t *event, char *application) {
+ int rv;
+
+@@ -235,6 +328,15 @@
+ return rv;
+ }
+
++/**
++ * Create a symlink, with necessary parent directories.
++ *
++ * @1 Hotplug event structure
++ * @2 Link target, with expandable keys
++ * @3 Link name, with expandable keys
++ *
++ * Returns: return value of symlink()
++ */
+ static int make_symlink(struct hotplug2_event_t *event, char *target, char *linkname) {
+ int rv;
+
+@@ -250,11 +352,50 @@
return rv;
}
-static int chown_chgrp(int action, char *file, char *param) {
++/**
++ * Chmod a given file.
++ *
++ * @1 Hotplug event structure
++ * @2 File name, with expandable keys
++ * @3 Chmod value, with expandable keys
++ *
++ * Returns: return value of chmod()
++ */
+static int chmod_file(struct hotplug2_event_t *event, char *file, char *value) {
+ int rv;
+
@@ -591,6 +1869,17 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+ return rv;
+}
+
++
++/**
++ * Change owner or group of a given file.
++ *
++ * @1 Hotplug event structure
++ * @2 Whether we chown or chgrp
++ * @3 Filename, with expandable keys
++ * @4 Group or user name, with expandable keys
++ *
++ * Returns: return value of chown()
++ */
+static int chown_chgrp(struct hotplug2_event_t *event, int action, char *file, char *param) {
struct group *grp;
struct passwd *pwd;
@@ -605,7 +1894,7 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
switch (action) {
case ACT_CHOWN:
pwd = getpwnam(param);
-@@ -265,11 +302,23 @@
+@@ -265,11 +406,37 @@
rv = chown(file, -1, grp->gr_gid);
break;
}
@@ -617,21 +1906,52 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+ return rv;
+}
+
-+static int print_debug(struct hotplug2_event_t *event) {
++/**
++ * Prints all uevent keys.
++ *
++ * @1 Hotplug event structure
++ *
++ * Returns: void
++ */
++static void print_debug(struct hotplug2_event_t *event) {
+ int i;
+
+ for (i = 0; i < event->env_vars_c; i++)
+ printf("%s=%s\n", event->env_vars[i].key, event->env_vars[i].value);
-+
-+ return 0;
}
-static int rule_condition_eval(struct hotplug2_event_t *event, struct condition_t *condition) {
++/**
++ * Evaluates a condition according to a given hotplug event structure.
++ *
++ * @1 Hotplug event structure
++ * @2 Condition to be evaluated
++ *
++ * Returns: 1 if match, 0 if no match, EVAL_NOT_AVAILABLE if unable to
++ * perform evaluation
++ */
+int rule_condition_eval(struct hotplug2_event_t *event, struct condition_t *condition) {
int rv;
char *event_value = NULL;
regex_t preg;
-@@ -347,11 +396,11 @@
+@@ -314,6 +481,16 @@
+ return EVAL_NOT_AVAILABLE;
+ }
+
++/**
++ * Executes a rule. Contains evaluation of all conditions prior
++ * to execution.
++ *
++ * @1 Hotplug event structure
++ * @2 The rule to be executed
++ *
++ * Returns: 0 if success, -1 if the whole event is to be
++ * discared, 1 if bail out of this particular rule was required
++ */
+ int rule_execute(struct hotplug2_event_t *event, struct rule_t *rule) {
+ int i, last_rv;
+
+@@ -347,11 +524,11 @@
last_rv = make_dev_from_event(event, rule->actions[i].parameter[0], strtoul(rule->actions[i].parameter[1], NULL, 0));
break;
case ACT_CHMOD:
@@ -645,7 +1965,7 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
break;
case ACT_SYMLINK:
last_rv = make_symlink(event, rule->actions[i].parameter[0], rule->actions[i].parameter[1]);
-@@ -365,6 +414,27 @@
+@@ -365,12 +542,49 @@
case ACT_SETENV:
last_rv = setenv(rule->actions[i].parameter[0], rule->actions[i].parameter[1], 1);
break;
@@ -654,15 +1974,23 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+ rmdir_p(rule->actions[i].parameter[0]);
+ break;
+ case ACT_DEBUG:
-+ last_rv = print_debug(event);
++ print_debug(event);
++ last_rv = 0;
+ break;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+int rule_flags(struct hotplug2_event_t *event, struct rule_t *rule) {
+ }
+ }
+
+ return 0;
+ }
+
++/**
++ * Sets the flags of the given rule.
++ *
++ * @1 Rule structure
++ *
++ * Returns: void
++ */
++void rule_flags(struct rule_t *rule) {
+ int i;
+
+ for (i = 0; i < rule->actions_c; i++) {
@@ -670,10 +1998,138 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
+ case ACT_FLAG_NOTHROTTLE:
+ rule->flags |= FLAG_NOTHROTTLE;
+ break;
- }
- }
++ }
++ }
++
++ return;
++}
++
++/**
++ * Checks whether the given character should initiate
++ * further parsing.
++ *
++ * @1 Character to examine
++ *
++ * Returns: 1 if it should, 0 otherwise
++ */
+ static inline int isinitiator(int c) {
+ switch (c) {
+ case ',':
+@@ -383,6 +597,16 @@
+ return 0;
+ }
+
++/**
++ * Appends a character to a buffer. Enlarges if necessary.
++ *
++ * @1 Pointer to the buffer
++ * @2 Pointer to buffer size
++ * @3 Pointer to last buffer character
++ * @4 Appended character
++ *
++ * Returns: void
++ */
+ static inline void add_buffer(char **buf, int *blen, int *slen, char c) {
+ if (*slen + 1 >= *blen) {
+ *blen = *blen + 64;
+@@ -394,6 +618,14 @@
+ *slen += 1;
+ }
+
++/**
++ * Parses a string into a syntactically acceptable value.
++ *
++ * @1 Input string
++ * @2 Pointer to the new position
++ *
++ * Returns: Newly allocated string.
++ */
+ static char *rules_get_value(char *input, char **nptr) {
+ int quotes = QUOTES_NONE;
+ char *ptr = input;
+@@ -471,6 +703,16 @@
+ return buf;
+ }
+
++/**
++ * Releases all memory associated with the ruleset. TODO: Make
++ * the behavior same for all _free() functions, ie. either
++ * release the given pointer itself or keep it, but do it
++ * in all functions!
++ *
++ * @1 The ruleset to be freed
++ *
++ * Returns: void
++ */
+ void rules_free(struct rules_t *rules) {
+ int i, j, k;
-@@ -518,6 +588,9 @@
+@@ -492,10 +734,53 @@
+ free(rules->rules);
+ }
+
+-struct rules_t *rules_from_config(char *input) {
+- int status = STATUS_KEY, terminate;
++/**
++ * Includes a rule file.
++ *
++ * @1 Filename
++ * @2 The ruleset structure
++ *
++ * Returns: 0 if success, -1 otherwise
++ */
++int rules_include(const char *filename, struct rules_t **return_rules) {
++ struct filemap_t filemap;
++ struct rules_t *rules;
++
++ if (map_file(filename, &filemap)) {
++ ERROR("rules parse","Unable to open/mmap rules file.");
++ return -1;
++ }
++
++ rules = rules_from_config((char*)(filemap.map), *return_rules);
++ if (rules == NULL) {
++ ERROR("rules parse","Unable to parse rules file.");
++ return -1;
++ }
++
++ unmap_file(&filemap);
++
++ return 0;
++}
++
++/**
++ * Parses an entire file of rules.
++ *
++ * @1 The whole file in memory or mmap'd
++ *
++ * Returns: A newly allocated ruleset.
++ */
++struct rules_t *rules_from_config(char *input, struct rules_t *return_rules) {
++ #define last_rule return_rules->rules[return_rules->rules_c - 1]
++ int nested;
++ int status;
++ int terminate;
+ char *buf;
+- struct rules_t *return_rules;
++
++ /*
++ * TODO: cleanup
++ *
++ * BIIIG cleanup... Use callbacks for actions and for internal actions.
++ */
+
+ int i, j;
+ struct key_rec_t conditions[] = { /*NOTE: We never have parameters for conditions. */
+@@ -506,6 +791,7 @@
+ {"!~", 0, COND_NMATCH_RE},
+ {NULL, 0, -1}
+ };
++
+ struct key_rec_t actions[] = {
+ /*one line / one command*/
+ {"run", 1, ACT_RUN_SHELL},
+@@ -518,6 +804,9 @@
{"chmod", 2, ACT_CHMOD},
{"chgrp", 2, ACT_CHGRP},
{"setenv", 2, ACT_SETENV},
@@ -683,9 +2139,77 @@ diff -urN -x.svn hotplug2-0.9/rules.c hotplug2/rules.c
/*symlink*/
{"symlink", 2, ACT_SYMLINK},
{"softlink", 2, ACT_SYMLINK},
-diff -urN -x.svn hotplug2-0.9/rules.h hotplug2/rules.h
+@@ -527,9 +816,19 @@
+ {NULL, 0, -1}
+ };
+
+- return_rules = xmalloc(sizeof(struct rules_t));
+- return_rules->rules_c = 1;
+- return_rules->rules = xmalloc(sizeof(struct rule_t) * return_rules->rules_c);
++ /*
++ * A little trick for inclusion.
++ */
++ if (return_rules == NULL) {
++ return_rules = xmalloc(sizeof(struct rules_t));
++ return_rules->rules_c = 1;
++ return_rules->rules = xmalloc(sizeof(struct rule_t) * return_rules->rules_c);
++ nested = 0;
++ } else {
++ nested = 1;
++ }
++
++ status = STATUS_KEY;
+
+ last_rule.actions = NULL;
+ last_rule.actions_c = 0;
+@@ -549,9 +848,26 @@
+ /* Skip to next line */
+ while (*input != '\0' && *input != '\n')
+ input++;
++
++ free(buf);
++ continue;
++ } else if (buf[0] == '$') {
++ buf++;
++
++ /*
++ * Warning, hack ahead...
++ */
++ if (!strcmp("include", buf)) {
++ buf = rules_get_value(input, &input);
++ if (rules_include(buf, &return_rules)) {
++ ERROR("rules_include", "Unable to include ruleset '%s'!", buf);
++ }
++ }
++
++ free(buf);
+ continue;
+ }
+-
++
+ switch (status) {
+ case STATUS_KEY:
+ last_rule.conditions_c++;
+@@ -684,8 +1000,14 @@
+ return_rules->rules_c--;
+ return return_rules;
+ } else {
+- rules_free(return_rules);
+- free(return_rules);
++ /*
++ * We don't want to cleanup if we're nested.
++ */
++ if (!nested) {
++ rules_free(return_rules);
++ free(return_rules);
++ }
++
+ return NULL;
+ }
+ }
+diff -urN -x .svn hotplug2-0.9/rules.h hotplug2/rules.h
--- hotplug2-0.9/rules.h 2006-09-25 13:42:22.000000000 +0200
-+++ hotplug2/rules.h 2007-06-30 12:44:52.501430000 +0200
++++ hotplug2/rules.h 2007-07-09 02:01:10.962249500 +0200
@@ -24,9 +24,12 @@
#define ACT_CHGRP 6 /* chgrp <...> */
#define ACT_CHOWN 7 /* chown <...> */
@@ -700,7 +2224,7 @@ diff -urN -x.svn hotplug2-0.9/rules.h hotplug2/rules.h
#define EVAL_MATCH 1
#define EVAL_NOT_MATCH 0
-@@ -42,6 +45,11 @@
+@@ -42,6 +45,10 @@
#define STATUS_INITIATOR 3 /* ',' for next cond, '{' for block*/
#define STATUS_ACTION 4 /* viz ACT_* and '}' for end of block */
@@ -708,30 +2232,32 @@ diff -urN -x.svn hotplug2-0.9/rules.h hotplug2/rules.h
+#define FLAG_ALL 0xffffffff
+#define FLAG_NOTHROTTLE 1 /* We want this rule to ignore max_children limit */
+
-+
struct key_rec_t {
char *key;
int param;
-@@ -65,6 +73,8 @@
+@@ -65,6 +72,8 @@
struct action_t *actions;
int actions_c;
+
-+ int flags;
++ unsigned int flags;
};
struct rules_t {
-@@ -72,7 +82,9 @@
+@@ -72,8 +81,10 @@
int rules_c;
};
+int rule_condition_eval(struct hotplug2_event_t *, struct condition_t *);
int rule_execute(struct hotplug2_event_t *, struct rule_t *);
-+int rule_flags(struct hotplug2_event_t *, struct rule_t *);
++void rule_flags(struct rule_t *);
void rules_free(struct rules_t *);
- struct rules_t *rules_from_config(char *);
+-struct rules_t *rules_from_config(char *);
++struct rules_t *rules_from_config(char *, struct rules_t *);
-diff -urN -x.svn hotplug2-0.9/TODO hotplug2/TODO
+ #endif /* ifndef RULES_H*/
+Binary files hotplug2-0.9/.swp and hotplug2/.swp differ
+diff -urN -x .svn hotplug2-0.9/TODO hotplug2/TODO
--- hotplug2-0.9/TODO 1970-01-01 01:00:00.000000000 +0100
+++ hotplug2/TODO 2007-06-28 14:51:00.012934184 +0200
@@ -0,0 +1 @@