diff options
Diffstat (limited to 'package')
| -rw-r--r-- | package/base-files/files/etc/hotplug2-init.rules | 22 | ||||
| -rw-r--r-- | package/hotplug2/Makefile | 2 | ||||
| -rw-r--r-- | package/hotplug2/files/hotplug2.rules | 18 | ||||
| -rw-r--r-- | package/hotplug2/patches/100-svn_update.patch | 1674 | 
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 @@ | 
