From: Felix Fietkau Date: Mon, 9 Jul 2007 00:13:47 +0000 (+0000) Subject: hotplug2 update - include hotplug2-init.rules from hotplug2.rules, fix permissions... X-Git-Tag: reboot~28737 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fopenwrt.git;a=commitdiff_plain;h=0e387805fbb995d12a6c71337f8873ec61326876 hotplug2 update - include hotplug2-init.rules from hotplug2.rules, fix permissions of various devices (fixes #2052) SVN-Revision: 7892 --- diff --git a/package/base-files/files/etc/hotplug2-init.rules b/package/base-files/files/etc/hotplug2-init.rules index 098ad047a7..bcc4c6a9ec 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 ee35bd6fce..559732bf4c 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 3d7df41ef6..a6697ae86d 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 2844c6eb4f..283e613719 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 + + #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 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 + #include + ++/** ++ * 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 + + #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,38 +2224,40 @@ 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 */ +#define FLAG_UNSET 0 +#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 @@