[rb532] switch to 2.6.30-rc7, fixes #5111
[openwrt.git] / package / hotplug2 / patches / 100-svn_update.patch
1 diff -urN -x .svn hotplug2-0.9/AUTHORS hotplug2/AUTHORS
2 --- hotplug2-0.9/AUTHORS        2006-10-08 18:13:50.000000000 +0200
3 +++ hotplug2/AUTHORS    2007-06-30 12:59:20.459674000 +0200
4 @@ -1,7 +1,11 @@
5   Authors:
6  ----------
7  iSteve <isteve@bofh.cz>
8 -Tomas Janousek <tomi@nomi.cz>
9 +
10 + Contributions:
11 +----------------
12 +nbd (rules override patch, various fixes, suggestions, testing etc.)
13 +Tomas Janousek <tomi@nomi.cz> (Makefiles, SVN hosting)
14  
15   Thanks to:
16  ------------
17 @@ -10,5 +14,9 @@
18  Randy Dunlap (help with isapnpmap)
19  Igor2 (provided testing machines)
20  yanek (provided testing machines)
21 +Zdenek Styblik (provided testing OpenWRT device)
22 +OpenWRT team (for trusting this project)
23 +mtu (debugging, testing, ideas)
24 +mnemoc (trivial sanity changes on makefiles, linux24 compat patches)
25  
26 -...anyone taking more than a short peek at the software.
27 \ No newline at end of file
28 +...anyone taking more than a short peek at the software.
29 diff -urN -x .svn hotplug2-0.9/Changelog hotplug2/Changelog
30 --- hotplug2-0.9/Changelog      2006-10-08 15:32:31.000000000 +0200
31 +++ hotplug2/Changelog  2007-07-09 01:17:14.865503750 +0200
32 @@ -1,3 +1,13 @@
33 +0.9 - 1.0:
34 +* Add --set-rules-file.
35 +* Allow any ACTION.
36 +* Add 'printdebug' rule.
37 +* Fix chmod, chown, chgrp.
38 +* Use octal for chmod and makedev.
39 +* Add 'nothrottle' flag, allowing overriding max-children from a rule
40 +* Various bugfixes
41 +* Code comments
42 +
43  0.8 - 0.9:
44  * Use signals to handle children.
45  * Separate info and debugging output.
46 @@ -44,4 +54,4 @@
47  * Add more actions.
48  * Significant cleanup of rules handling.
49  * Better error reporting.
50
51 \ No newline at end of file
52
53 diff -urN -x .svn hotplug2-0.9/common.mak hotplug2/common.mak
54 --- hotplug2-0.9/common.mak     2006-09-26 01:03:08.000000000 +0200
55 +++ hotplug2/common.mak 2007-07-09 01:17:14.869504000 +0200
56 @@ -1,6 +1,6 @@
57  # vim:set sw=8 nosta:
58  
59 -CFLAGS=-Os -DHAVE_RULES -Wall -g
60 +CFLAGS=-Os -DHAVE_RULES -Wall -g -Wextra
61  LDFLAGS=-g
62  
63  INSTALL=install -c -m 644
64 @@ -10,7 +10,7 @@
65  .PHONY: all clean dep install install-recursive clean-recursive \
66         dep-recursive all-recursive
67  
68 -MAKEDEP=-gcc $(CFLAGS) -MM $(wildcard *.c *.cc) > .depend
69 +MAKEDEP=-$(CC) $(CFLAGS) -MM $(wildcard *.c *.cc) > .depend
70  dep: dep-recursive
71         $(MAKEDEP)
72  .depend:
73 diff -urN -x .svn hotplug2-0.9/docs/hotplug2.8 hotplug2/docs/hotplug2.8
74 --- hotplug2-0.9/docs/hotplug2.8        2006-09-26 09:23:36.000000000 +0200
75 +++ hotplug2/docs/hotplug2.8    2007-06-28 14:50:59.874955160 +0200
76 @@ -22,6 +22,8 @@
77  .TP 
78  \fB\-\-dumb\fR, \fB\-\-no\-dumb\fR
79  Run or do not run hotplug2 in dumb mode. Dumb mode means that rules are being ignored, the only action taken is mload modules to all devices whose uevent exports MODALIAS. Only available if compiled with HAVE_RULES.
80 +\fB\-\-override\fR, \fB\-\-no\-override\fR
81 +Allows hotplug2 behavior overriding for different rules, using various flags. See hotplug2 rules documentation for details. The default is not to allow overriding, the flags are therefore ignored.
82  .TP 
83  \fB\-\-max\-children <value>\fR
84  Set the value of maximum children hotplug2 may have running simultaneously. Default is 20.
85 @@ -31,6 +33,8 @@
86  .TP 
87  \fB\-\-set\-modprobe\-cmd <cmd>\fR
88  Sets the application used to perform modprobe. It only gets used in dumb mode. Default is to autodetect: if '/bin/modprobe' is from module\-init\-tools, use '/sbin/modprobe', otherwise use '/sbin/hotplug2\-modwrap'.
89 +\fB\-\-set\-rules\-file <file>\fR
90 +Sets the path to the file containing hotplug2 rules.
91  .SH "SIGNALS"
92  .TP 
93  \fBSIGUSR1\fR
94 diff -urN -x .svn hotplug2-0.9/docs/hotplug2.rules.doc hotplug2/docs/hotplug2.rules.doc
95 --- hotplug2-0.9/docs/hotplug2.rules.doc        2006-09-26 10:19:46.000000000 +0200
96 +++ hotplug2/docs/hotplug2.rules.doc    2007-06-28 14:50:59.872955464 +0200
97 @@ -11,12 +11,12 @@
98         [... [...]]
99  }
100  
101 -Comments are allowed, they are prefixed with '#', treating the whole rest of the
102 -line as comment. Please note that comments in place of action parameters are not
103 -supported.
104 +Comments are allowed, they are prefixed with '#', treating the whole rest of
105 +the line as comment. Please note that comments in place of action parameters
106 +are not supported.
107  
108 -The <key> is one of the environmental variables that have been obtained by the
109 -uevent netlink. 
110 +The <key> is one of the environmental variables that have been obtained by
111 +the uevent netlink. 
112  
113   COMMON KEYS
114   -----------
115 @@ -66,9 +66,9 @@
116    -------
117  
118   * run <...>
119 -       Execute an application using system();, takes one parameter. Note that
120 -       the application has set all environmental variables read by uevent
121 -       netlink.
122 +       Execute an application using system();, takes one parameter. Note
123 +       that the application has set all environmental variables read by 
124 +       uevent netlink.
125  
126   * break
127         Break the processing of the current block of actions.
128 @@ -86,23 +86,22 @@
129  
130   * exec <application [parameter [parameter [...]]]> ;
131         Execute an application. Takes variable number of parameters, but the
132 -       last parameter must be terminated with semicolon. Again, all variables
133 -       are set as environmental.
134 +       last parameter must be terminated with semicolon. Again, all
135 +       variables are set as environmental.
136         
137 -       If you need to escape the ';', use '\\;'. Only applies for actions with
138 -       variable number of parameters.
139 +       If you need to escape the ';', use '\\;'. Only applies for actions
140 +       with variable number of parameters.
141         
142   * makedev <path> <mode>
143 -       Create a device with given mode. The mode is not in octal unless it
144 -       starts with '0', eg. "0644" != "644".
145 +       Create a device with given mode. Mode is interpreted as octal.
146         
147         Major, minor and devpath must be set for makedev to be able to work.
148         Tests for these variables are also performed internally in makedev
149         function.
150  
151   * symlink <target> <linkname>
152 -       Create a symbolic link (symlink, also known as soft link) pointing at
153 -       target with name linkname.
154 +       Create a symbolic link (symlink, also known as soft link) pointing
155 +       at target with name linkname.
156         
157   * chown <path> <owner name>
158         Change owner of path to owner name.
159 @@ -111,12 +110,32 @@
160         Change group of path to group name.
161         
162   * chmod <path> <mode>
163 -       Change mode of path to given mode. Like with makedev, heading '0' is
164 -       necessary for the mode to be interpreted as octal.
165 +       Change mode of path to given mode. Mode is interpreted as octal.
166  
167   * setenv <key> <value>
168         Sets environmental variable key to the given value. If an env var
169         of the given name already exists, it gets overwritten.
170 +
171 + * printdebug
172 +       Prints all variables read from kernel.
173 +
174 + FLAGS
175 + -----
176 +
177 +Flags are, syntactically, just like actions; their semantical value is different however.
178 +Instead of doing something, they instead change the general behavior of the processing
179 +of the given rule.
180 +
181 +Note that for flags to work, you also have to invoke it with --override.
182 +
183 +Currently, only one flag is implemented:
184 +
185 + * nothrottle
186 +       Forcibly overrides hotplug2 throttling mechanism. If _all_ rules that match
187 +       the given kernel event have 'nothrottle' set, hotplug2 will not wait for
188 +       children count to get under max-children limit. That allows to throttle
189 +       eg. helper application execution or modprobes, but yet keep node devices
190 +       fast.
191         
192   ESCAPING
193   --------
194 @@ -136,8 +155,9 @@
195   SAMPLE CONFIG
196   -------------
197  
198 -Below is a sample hotplug2.rules file. It loads modules to all available devices
199 -quietly and creates device nodes for block devices.
200 +Below is a sample hotplug2.rules file. It loads modules to all available
201 +devices quietly and creates device nodes for block devices. Note that this
202 +sample is not very viable for real life usage.
203  ---------------------------------------------------------------------------------
204  MODALIAS is set {
205         exec modprobe -q %MODALIAS% ;
206 @@ -146,3 +166,33 @@
207  SUBSYSTEM == block, DEVPATH is set, MAJOR is set, MINOR is set {
208         makedev /dev/%DEVICENAME% 0644
209  }
210 +
211 +
212 +Please find also the more complex set of rules, dedicated to handling most
213 +common needs.
214 +---------------------------------------------------------------------------------
215 +#For debugging
216 +#ACTION is set {
217 +#      printdebug
218 +#}
219 +
220 +# Load modules (what old hotplug did)
221 +MODALIAS is set {
222 +       exec modprobe -q %MODALIAS% ;
223 +}
224 +
225 +# Create device nodes
226 +DEVPATH is set, MAJOR is set, MINOR is set {
227 +       makedev /dev/%DEVICENAME% 0644
228 +}
229 +
230 +# Mount a USB flashdisk
231 +ACTION == add, PHYSDEVPATH ~~ "/usb[0-9]*/", DEVICENAME ~~ "^sd[a-z][0-9]+$", DEVPATH is set, MAJOR is set, MINOR is set {
232 +       makedev /dev/%DEVICENAME% 0644
233 +       exec mount /dev/%DEVICENAME% /mnt/%DEVICENAME%
234 +}
235 +
236 +# Unmount a USB flashdisk
237 +ACTION == remove, PHYSDEVPATH ~~ "/usb[0-9]*/", DEVICENAME ~~ "^sd[a-z][0-9]+$", MAJOR is set, MINOR is set {
238 +       exec umount /mnt/%DEVICENAME%
239 +}
240 diff -urN -x .svn hotplug2-0.9/docs/Makefile hotplug2/docs/Makefile
241 --- hotplug2-0.9/docs/Makefile  2006-09-26 00:27:02.000000000 +0200
242 +++ hotplug2/docs/Makefile      2007-06-28 14:50:59.875955008 +0200
243 @@ -2,12 +2,13 @@
244  
245  BINS=
246  SUBDIRS=
247 -
248 +DESTDIR=
249 +MANDIR=/usr/share/man
250  
251  all:
252  
253  install:
254 -       $(INSTALL) $(wildcard *.8) /usr/share/man/man8/
255 +       $(INSTALL) $(wildcard *.8) $(DESTDIR)$(MANDIR)/man8/
256  
257  
258  include ../common.mak
259 diff -urN -x .svn hotplug2-0.9/examples/Makefile hotplug2/examples/Makefile
260 --- hotplug2-0.9/examples/Makefile      2006-09-26 01:03:08.000000000 +0200
261 +++ hotplug2/examples/Makefile  2007-06-28 14:50:59.991937376 +0200
262 @@ -2,19 +2,23 @@
263  
264  BINS=
265  SUBDIRS=
266 +DESTDIR=
267 +KERNELVER=`uname -r`
268  
269  
270  all:
271  
272  install:
273 -       case "`uname -r`" in \
274 -               2.6.*) \
275 -               $(INSTALL) hotplug2.rules-2.6kernel /etc/hotplug2.rules \
276 -               ;; \
277 -               *) \
278 -               $(INSTALL) hotplug2.rules-2.4kernel /etc/hotplug2.rules \
279 -               ;; \
280 -       esac
281 +       if ! [ -e "/etc/hotplug2.rules" ]; then \
282 +               case "$(KERNELVER)" in \
283 +                       2.6.*) \
284 +                       $(INSTALL) hotplug2.rules-2.6kernel $(DESTDIR)/etc/hotplug2.rules \
285 +                       ;; \
286 +                       *) \
287 +                       $(INSTALL) hotplug2.rules-2.4kernel $(DESTDIR)/etc/hotplug2.rules \
288 +                       ;; \
289 +               esac; \
290 +       fi;
291  
292  
293  include ../common.mak
294 diff -urN -x .svn hotplug2-0.9/filemap_utils.c hotplug2/filemap_utils.c
295 --- hotplug2-0.9/filemap_utils.c        2006-09-25 12:14:12.000000000 +0200
296 +++ hotplug2/filemap_utils.c    2007-07-09 02:01:10.966249750 +0200
297 @@ -16,7 +16,15 @@
298  
299  #include "filemap_utils.h"
300  
301 -int map_file(char *filename, struct filemap_t *filemap) {
302 +/**
303 + * Basic open/mmap wrapper to make things simpler.
304 + *
305 + * @1 Filename of the mmaped file
306 + * @2 Pointer to filemap structure
307 + *
308 + * Returns: 0 if success, 1 otherwise
309 + */
310 +int map_file(const char *filename, struct filemap_t *filemap) {
311         struct stat statbuf;
312         
313         filemap->fd = open(filename, O_RDONLY);
314 @@ -40,9 +48,16 @@
315         return 0;
316  }
317  
318 +/**
319 + * Basic close/munmap wrapper.
320 + *
321 + * @1 Pointer to filemap structure
322 + *
323 + * Returns: always 0
324 + */
325  int unmap_file(struct filemap_t *filemap) {
326 -       close(filemap->fd);
327         munmap(filemap->map, filemap->size);
328 +       close(filemap->fd);
329         
330         return 0;
331  }
332 diff -urN -x .svn hotplug2-0.9/filemap_utils.h hotplug2/filemap_utils.h
333 --- hotplug2-0.9/filemap_utils.h        2006-09-25 22:24:36.000000000 +0200
334 +++ hotplug2/filemap_utils.h    2007-07-09 02:01:10.962249500 +0200
335 @@ -14,6 +14,6 @@
336         void *map;
337  };
338  
339 -int map_file(char *, struct filemap_t *);
340 +int map_file(const char *, struct filemap_t *);
341  int unmap_file(struct filemap_t *);
342  #endif
343 diff -urN -x .svn hotplug2-0.9/hotplug2.c hotplug2/hotplug2.c
344 --- hotplug2-0.9/hotplug2.c     2006-10-08 15:18:23.000000000 +0200
345 +++ hotplug2/hotplug2.c 2007-07-09 02:01:10.962249500 +0200
346 @@ -23,7 +23,9 @@
347  #include <linux/netlink.h>
348  
349  #include "mem_utils.h"
350 +#include "filemap_utils.h"
351  #include "hotplug2.h"
352 +#include "hotplug2_utils.h"
353  #include "rules.h"
354  #include "childlist.h"
355  
356 @@ -32,10 +34,16 @@
357                                         child == NULL && \
358                                         highest_seqnum == get_kernel_seqnum())
359  
360 +/*
361 + * These variables are accessed from throughout the code.
362 + *
363 + * TODO: Move this into a hotplug2_t-like variable.
364 + */
365  event_seqnum_t highest_seqnum = 0;
366  pid_t coldplug_p;
367  int coldplug = 1;
368  int persistent = 0;
369 +int override = 0;
370  int max_child_c = 20;
371  int dumb = 0;
372  int terminate = 0;
373 @@ -45,6 +53,14 @@
374  
375  char *modprobe_command = NULL;
376  
377 +/**
378 + * Release all memory associated with an uevent read from kernel. The given
379 + * pointer is no longer valid, as it gets freed as well.
380 + *
381 + * @1 The event that is to be freed.
382 + *
383 + * Returns: void
384 + */
385  inline void free_hotplug2_event(struct hotplug2_event_t *event) {
386         int i;
387         
388 @@ -57,6 +73,13 @@
389         free(event);
390  }
391  
392 +/**
393 + * A trivial function determining the action that the uevent.
394 + *
395 + * @1 String containing the action name (null-terminated).
396 + *
397 + * Returns: Macro of the given action
398 + */
399  inline int get_hotplug2_event_action(char *action) {
400         if (!strcmp(action, "add"))
401                 return ACTION_ADD;
402 @@ -67,6 +90,14 @@
403         return ACTION_UNKNOWN;
404  }
405  
406 +/**
407 + * Looks up a value according to the given key.
408 + *
409 + * @1 A hotplug event structure
410 + * @2 Key for lookup
411 + *
412 + * Returns: The value of the key or NULL if no such key found
413 + */
414  char *get_hotplug2_value_by_key(struct hotplug2_event_t *event, char *key) {
415         int i;
416         
417 @@ -78,7 +109,16 @@
418         return NULL;
419  }
420  
421 -inline int add_hotplug2_event_env(struct hotplug2_event_t *event, char *item) {
422 +/**
423 + * Appends a key-value pair described by the second argument to the
424 + * hotplug event.
425 + *
426 + * @1 A hotplug event structure
427 + * @1 An item in format "key=value" to be appended
428 + *
429 + * Returns: 0 if success, -1 if the string is malformed
430 + */
431 +int add_hotplug2_event_env(struct hotplug2_event_t *event, char *item) {
432         char *ptr, *tmp;
433         
434         ptr = strchr(item, '=');
435 @@ -94,6 +134,8 @@
436         
437         /*
438          * Variables not generated by kernel but demanded nonetheless...
439 +        *
440 +        * TODO: Split this to a different function
441          */
442         if (!strcmp(item, "DEVPATH")) {
443                 event->env_vars_c++;
444 @@ -109,6 +151,15 @@
445         return 0;
446  }
447  
448 +/**
449 + * Duplicates all allocated memory of a source hotplug event
450 + * and returns a new hotplug event, an identical copy of the
451 + * source event.
452 + *
453 + * @1 Source hotplug event structure
454 + *
455 + * Returns: A copy of the source event structure
456 + */
457  inline struct hotplug2_event_t *dup_hotplug2_event(struct hotplug2_event_t *src) {
458         struct hotplug2_event_t *dest;
459         int i;
460 @@ -129,6 +180,14 @@
461         return dest;
462  }
463  
464 +/**
465 + * Parses a string into a hotplug event structurs.
466 + *
467 + * @1 The event string (not null terminated)
468 + * @2 The size of the event string
469 + *
470 + * Returns: A new event structure
471 + */
472  inline struct hotplug2_event_t *get_hotplug2_event(char *event_str, int size) {
473         char *ptr;
474         struct hotplug2_event_t *event;
475 @@ -161,59 +220,15 @@
476         return event;
477  }
478  
479 -inline event_seqnum_t get_kernel_seqnum() {
480 -       FILE *fp;
481 -       
482 -       char filename[64];
483 -       char seqnum[64];
484 -       
485 -       strcpy(filename, sysfs_seqnum_path);
486 -       
487 -       fp = fopen(filename, "r");
488 -       if (fp == NULL)
489 -               return 0;
490 -       
491 -       fread(seqnum, 1, 64, fp);
492 -       fclose(fp);
493 -       
494 -       return strtoull(seqnum, NULL, 0);
495 -}
496 -
497 -inline int init_netlink_socket() {
498 -       int netlink_socket;
499 -       struct sockaddr_nl snl;
500 -       int buffersize = 16 * 1024 * 1024;
501 -       
502 -       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
503 -       snl.nl_family = AF_NETLINK;
504 -       snl.nl_pid = getpid();
505 -       snl.nl_groups = 1;
506 -       netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
507 -       if (netlink_socket == -1) {
508 -               ERROR("opening netlink","Failed socket: %s.", strerror(errno));
509 -               return -1;
510 -       }
511 -       
512 -       if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize))) {
513 -               ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
514 -               
515 -               /* Somewhat safe default. */
516 -               buffersize = 106496;
517 -               
518 -               if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize))) {
519 -                       ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
520 -               }
521 -       }
522 -       
523 -       if (bind(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
524 -               ERROR("opening netlink","Failed bind: %s.", strerror(errno));
525 -               close(netlink_socket);
526 -               return -1;
527 -       }
528 -       
529 -       return netlink_socket;
530 -}
531 -
532 +/**
533 + * Evaluates an argument into a true/false value.
534 + *
535 + * @1 argument
536 + * @2 argument flag
537 + * @3 pointer to output value
538 + *
539 + * Returns: 0 if success, -1 otherwise
540 + */
541  int get_bool_opt(char *argv, char *name, int *value) {
542         int rv = -1;
543         
544 @@ -238,7 +253,13 @@
545         }
546  }
547  
548 -void cleanup(void) {
549 +/**
550 + * Performs a cleanup; closes uevent socket, resets signal
551 + * handlers, waits for all the children.
552 + *
553 + * Returns: void
554 + */
555 +void cleanup() {
556         pid_t p;
557         
558         close(netlink_socket);
559 @@ -254,6 +275,13 @@
560         INFO("cleanup", "All children terminated.");
561  }
562  
563 +/**
564 + * Handles all signals.
565 + *
566 + * @1 Signal identifier
567 + *
568 + * Returns: void
569 + */
570  void sighandler(int sig) {
571         pid_t p;
572         
573 @@ -313,6 +341,14 @@
574  }
575  
576  #ifdef HAVE_RULES
577 +/**
578 + * Execute all rules for this particular event.
579 + *
580 + * @1 Hotplug event structure
581 + * @2 Rules structure, containing array of rules
582 + *
583 + * Returns: void
584 + */
585  void perform_action(struct hotplug2_event_t *event, struct rules_t *rules) {
586         int i, rv;
587         
588 @@ -324,13 +360,72 @@
589         
590         free_hotplug2_event(event);
591  }
592 +
593 +/**
594 + * Iterates through all rules, and performs an AND between all flags that
595 + * would apply during execution (ie. all rules that have conditions matching
596 + * the hotplug event).
597 + *
598 + * @1 Hotplug event structure
599 + * @2 Rules structure, containing array of rules
600 + *
601 + * Returns: Flags that apply to all matching rules
602 + */
603 +int flags_eval(struct hotplug2_event_t *event, struct rules_t *rules) {
604 +       int flags = FLAG_ALL;
605 +       int match = 0;
606 +       int i, j;
607 +
608 +       for (i = 0; i < rules->rules_c; i++) {
609 +               match = 1;
610 +
611 +               for (j = 0; j < rules->rules[i].conditions_c; j++) {
612 +                       if (rule_condition_eval(event, &rules->rules[i].conditions[j]) != EVAL_MATCH) {
613 +                               match = 0;
614 +                               break;
615 +                       }
616 +               }
617 +
618 +               /*
619 +                * Logical AND between flags we've got already and
620 +                * those we're adding.
621 +                */
622 +               if (match) {
623 +                       rule_flags(&rules->rules[i]);
624 +                       flags &= rules->rules[i].flags;
625 +               }
626 +       }
627 +
628 +       /*
629 +        * A little trick; if no rule matched, we return FLAG_ALL
630 +        * and have it skipped completely.
631 +        */
632 +
633 +       return flags;
634 +}
635 +#else
636 +#define perform_action(event, rules)
637  #endif
638  
639 +/**
640 + * Blindly modprobe the modalias, nothing more.
641 + *
642 + * @1 Hotplug event structure
643 + * @2 Modalias to be loaded
644 + *
645 + * Returns: void
646 + */
647  void perform_dumb_action(struct hotplug2_event_t *event, char *modalias) {
648         free_hotplug2_event(event);
649         execl(modprobe_command, modprobe_command, "-q", modalias, NULL);
650  }
651  
652 +/**
653 + * Attempt to figure out whether our modprobe command can handle modalias.
654 + * If not, use our own wrapper.
655 + *
656 + * Returns: 0 if success, -1 otherwise
657 + */
658  int get_modprobe_command() {
659         pid_t p;
660         int fds[2];
661 @@ -381,6 +476,9 @@
662  }
663  
664  int main(int argc, char *argv[]) {
665 +       /*
666 +        * TODO, cleanup
667 +        */
668         static char buffer[UEVENT_BUFFER_SIZE+512];
669         struct hotplug2_event_t *tmpevent;
670         char *modalias, *seqnum;
671 @@ -390,28 +488,39 @@
672         int size;
673         int rv = 0;
674         int i;
675 +       unsigned int flags;
676         char *coldplug_command = NULL;
677 +       char *rules_file = HOTPLUG2_RULE_PATH;
678         sigset_t block_mask;
679         
680         struct rules_t *rules = NULL;
681 -       struct stat statbuf;
682 -       void *filemap;
683 -       int rule_fd;
684 +       struct filemap_t filemap;
685  
686         struct options_t bool_options[] = {
687                 {"persistent", &persistent},
688                 {"coldplug", &coldplug},
689                 {"udevtrigger", &coldplug},     /* compatibility */
690 +               {"override", &override},
691  #ifdef HAVE_RULES
692                 {"dumb", &dumb},
693  #endif
694                 {NULL, NULL}
695         };
696         
697 +       /*
698 +        * We parse all the options...
699 +        */
700         for (argc--; argc > 0; argc--) {
701                 argv++;
702 +               /*
703 +                * TODO, cleanup
704 +                */
705                 for (i = 0; bool_options[i].name != NULL; i++) {
706                         if (!get_bool_opt(*argv, bool_options[i].name, bool_options[i].value)) {
707 +                               /*
708 +                                * Bool options are --option or --no-options. If we handled
709 +                                * it, quit iterating.
710 +                                */
711                                 break;
712                         } else {
713                                 if (!strcmp(*argv, "--max-children")) {
714 @@ -435,52 +544,52 @@
715                                                 break;
716                                         
717                                         modprobe_command = *argv;
718 +                               } else if (!strcmp(*argv, "--set-rules-file")) {
719 +                                       argv++;
720 +                                       argc--;
721 +                                       if (argc <= 0)
722 +                                               break;
723 +                                       
724 +                                       rules_file = *argv;
725                                 }
726                         }
727                 }
728         }
729         
730 -#ifdef HAVE_RULES
731 +#ifndef HAVE_RULES
732 +       /*
733 +        * We don't use rules, so we use dumb mode only.
734 +        */
735 +       dumb = 1;
736 +#else
737 +       /*
738 +        * We're not in dumb mode, parse the rules. If we fail,
739 +        * faillback to dumb mode.
740 +        */
741         if (!dumb) {
742 -               filemap = MAP_FAILED;
743 -               rule_fd = open(HOTPLUG2_RULE_PATH, O_RDONLY | O_NOATIME);
744 -               if (rule_fd == -1) {
745 -                       dumb = 1;
746 -                       ERROR("rules parse","Unable to open rules file: %s.", strerror(errno));
747 -                       goto end_rules;
748 -               }
749 -               
750 -               if (fstat(rule_fd, &statbuf)) {
751 -                       dumb = 1;
752 -                       ERROR("rules parse","Unable to stat rules file: %s.", strerror(errno));
753 -                       goto end_rules;
754 -               }
755 -               
756 -               filemap = mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED, rule_fd, 0);
757 -               if (filemap == MAP_FAILED) {
758 +               if (map_file(rules_file, &filemap)) {
759 +                       ERROR("rules parse","Unable to open/mmap rules file.");
760                         dumb = 1;
761 -                       ERROR("rules parse","Unable to mmap rules file: %s.", strerror(errno));
762                         goto end_rules;
763                 }
764                 
765 -               rules = rules_from_config((char*)filemap);
766 +               rules = rules_from_config((char*)(filemap.map), NULL);
767                 if (rules == NULL) {
768                         ERROR("rules parse","Unable to parse rules file.");
769                         dumb = 1;
770                 }
771 +
772 +               unmap_file(&filemap);
773                 
774  end_rules:     
775 -               if (filemap != MAP_FAILED)
776 -                       munmap(filemap, statbuf.st_size);
777 -               if (rule_fd != -1)
778 -                       close(rule_fd);
779 -               
780                 if (dumb == 1)
781                         ERROR("rules parse","Parsing rules failed, switching to dumb mode.");
782 -       } else if (!modprobe_command)
783 -#else
784 -       if (dumb && !modprobe_command)
785 +       } else
786  #endif
787 +       /*
788 +        * No modprobe command specified, let's autodetect it.
789 +        */
790 +       if (!modprobe_command)
791         {
792                 if (get_modprobe_command()) {
793                         ERROR("modprobe_command","Unable to autodetect modprobe command.");
794 @@ -489,7 +598,10 @@
795                 DBG("modprobe_command", "Using modprobe: `%s'.", modprobe_command);
796         }
797         
798 -       netlink_socket = init_netlink_socket();
799 +       /*
800 +        * Open netlink socket to read the uevents
801 +        */
802 +       netlink_socket = init_netlink_socket(NETLINK_BIND);
803         
804         if (netlink_socket == -1) {
805                 ERROR("netlink init","Unable to open netlink socket.");
806 @@ -503,6 +615,9 @@
807         signal(SIGINT, sighandler);
808         signal(SIGCHLD, sighandler);
809         
810 +       /*
811 +        * If we desire coldplugging, we initiate it right now.
812 +        */
813         if (coldplug) {
814                 if (coldplug_command == NULL)
815                         coldplug_command = UDEVTRIGGER_COMMAND;
816 @@ -523,10 +638,19 @@
817                 coldplug_p = FORK_FINISHED;
818         }
819         
820 +       /*
821 +        * Main loop reading uevents
822 +        */
823         while (!terminate) {
824 +               /*
825 +                * Read the uevent packet
826 +                */
827                 size = recv(netlink_socket, &buffer, sizeof(buffer), 0);
828                 recv_errno = errno;
829         
830 +               /*
831 +                * Parse the event into an event structure
832 +                */
833                 tmpevent = get_hotplug2_event(buffer, size);
834                 
835                 if (tmpevent == NULL) {
836 @@ -534,26 +658,61 @@
837                         continue;
838                 }
839                 
840 +               /*
841 +                * Look up two important items of the event
842 +                */
843                 modalias = get_hotplug2_value_by_key(tmpevent, "MODALIAS");
844                 seqnum = get_hotplug2_value_by_key(tmpevent, "SEQNUM");
845 -               
846 +
847 +               /*
848 +                * Seqnum is necessary not to end up in a race with the kernel.
849 +                */
850                 if (seqnum == NULL) {
851                         free_hotplug2_event(tmpevent);
852                         ERROR("reading events", "Malformed event read (missing SEQNUM).");
853                         continue;
854                 }
855                 
856 +               /*
857 +                * Maintain seqnum continuity
858 +                */
859                 cur_seqnum = strtoull(seqnum, NULL, 0);
860                 if (cur_seqnum > highest_seqnum)
861                         highest_seqnum = cur_seqnum;
862                 
863 -               if (tmpevent->action == ACTION_ADD && (!dumb || modalias != NULL)) {
864 +               /*
865 +                * If we are in smart mode, we'll always pass. If we're in dumb mode,
866 +                * we only pass events that have 'add' action and have modalias set.
867 +                */
868 +               if ((dumb && tmpevent->action == ACTION_ADD && modalias != NULL) || (!dumb)) {
869 +                       /*
870 +                        * Pre-evaluation of the flags
871 +                        */
872 +                       if (!dumb && override) {
873 +                               flags = flags_eval(tmpevent, rules);
874 +
875 +                               DBG("flags", "flag returned: %8x", flags);
876 +
877 +                               if (flags == FLAG_ALL)
878 +                                       continue;
879 +                       } else {
880 +                               flags = FLAG_UNSET;
881 +                       }
882 +
883                         /* 
884                          * We have more children than we want. Wait until SIGCHLD handler reduces
885                          * their numbers.
886 +                        *
887 +                        * Unless, of course, we've specified otherwise and no rules that match
888 +                        * need throttling.
889                          */
890 -                       while (child_c >= max_child_c) {
891 -                               usleep(HOTPLUG2_THROTTLE_INTERVAL);
892 +                       if (!flags & FLAG_NOTHROTTLE) {
893 +                               /*
894 +                                * Okay, throttle away!
895 +                                */
896 +                               while (child_c >= max_child_c) {
897 +                                       usleep(HOTPLUG2_THROTTLE_INTERVAL);
898 +                               }
899                         }
900                         
901                         sigemptyset(&block_mask);
902 @@ -562,17 +721,18 @@
903                         p = fork();
904                         switch (p) {
905                                 case -1:
906 -                                       ERROR("event","fork failed: %s.", strerror(errno));
907 +                                       ERROR("event", "fork failed: %s.", strerror(errno));
908                                         break;
909                                 case 0:
910 +                                       /*
911 +                                        * TODO: We do not have to dup here, or do we?
912 +                                        */
913                                         sigprocmask(SIG_UNBLOCK, &block_mask, 0);
914                                         signal(SIGCHLD, SIG_DFL);
915                                         signal(SIGUSR1, SIG_DFL);
916 -#ifdef HAVE_RULES
917                                         if (!dumb)
918                                                 perform_action(dup_hotplug2_event(tmpevent), rules);
919                                         else
920 -#endif
921                                                 perform_dumb_action(dup_hotplug2_event(tmpevent), modalias);
922                                         exit(0);
923                                         break;
924 @@ -593,12 +753,10 @@
925         signal(SIGINT, SIG_DFL);
926         signal(SIGCHLD, SIG_DFL);
927         
928 -#ifdef HAVE_RULES
929         if (!dumb) {
930                 rules_free(rules);
931                 free(rules);
932         }
933 -#endif
934  
935         cleanup();
936         
937 diff -urN -x .svn hotplug2-0.9/hotplug2-dnode.c hotplug2/hotplug2-dnode.c
938 --- hotplug2-0.9/hotplug2-dnode.c       2006-09-26 17:35:35.000000000 +0200
939 +++ hotplug2/hotplug2-dnode.c   2007-07-09 01:17:14.869504000 +0200
940 @@ -27,6 +27,7 @@
941  
942  #include "mem_utils.h"
943  #include "hotplug2.h"
944 +#include "hotplug2_utils.h"
945  #include "parser_utils.h"
946  
947  #define MODALIAS_MAX_LEN               1024
948 @@ -45,59 +46,17 @@
949  
950  #define TEST_INPUT_BIT(i,bm)   (bm[i / BITS_PER_LONG] & (((unsigned long)1) << (i%BITS_PER_LONG)))
951  
952 -int init_netlink_socket() {
953 -       int netlink_socket;
954 -       struct sockaddr_nl snl;
955 -       int buffersize = 16 * 1024 * 1024;
956 -       
957 -       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
958 -       snl.nl_family = AF_NETLINK;
959 -       snl.nl_pid = getpid();
960 -       snl.nl_groups = 1;
961 -       netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
962 -       if (netlink_socket == -1) {
963 -               ERROR("opening netlink","Failed socket: %s.", strerror(errno));
964 -               return -1;
965 -       }
966 -       
967 -       if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUFFORCE, &buffersize, sizeof(buffersize))) {
968 -               ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
969 -               
970 -               /* Somewhat safe default. */
971 -               buffersize = 106496;
972 -               
973 -               if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUF, &buffersize, sizeof(buffersize))) {
974 -                       ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
975 -               }
976 -       }
977 -       
978 -       if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
979 -               ERROR("opening netlink","Failed bind: %s.", strerror(errno));
980 -               close(netlink_socket);
981 -               return -1;
982 -       }
983 -       
984 -       return netlink_socket;
985 -}
986 -
987 -inline event_seqnum_t get_kernel_seqnum() {
988 -       FILE *fp;
989 -       
990 -       char filename[64];
991 -       char seqnum[64];
992 -       
993 -       strcpy(filename, sysfs_seqnum_path);
994 -       
995 -       fp = fopen(filename, "r");
996 -       if (fp == NULL)
997 -               return 0;
998 -       
999 -       fread(seqnum, 1, 64, fp);
1000 -       fclose(fp);
1001 -       
1002 -       return strtoull(seqnum, NULL, 0);
1003 -}
1004 -
1005 +/**
1006 + * Parses a bitmap; output is a list of offsets of bits of a bitmap
1007 + * of arbitrary size that are set to 1.
1008 + *
1009 + * @1 Name of the bitmap parsed
1010 + * @2 The actual bitmap pointer
1011 + * @3 Lower boundary of the bitmap
1012 + * @4 Upper boundary of the bitmap
1013 + *
1014 + * Returns: Newly allocated string containing the offsets
1015 + */
1016  char *bitmap_to_bitstring(char name, unsigned long *bm, unsigned int min_bit, unsigned int max_bit)
1017  {
1018         char *rv;
1019 @@ -120,6 +79,15 @@
1020         return rv;
1021  }
1022  
1023 +/**
1024 + * Reverses the bitmap_to_bitstring function. 
1025 + *
1026 + * @1 Bitstring to be converted
1027 + * @2 Output bitmap
1028 + * @3 Size of the whole bitmap
1029 + *
1030 + * Returns: void
1031 + */
1032  void string_to_bitmap(char *input, unsigned long *bitmap, int bm_len) {
1033         char *token, *ptr;
1034         int i = 0;
1035 @@ -146,6 +114,14 @@
1036         } \
1037         bitmap = bitmap_to_bitstring(name, bitmap ## _bits, min, mapkey ## _MAX);
1038  
1039 +/**
1040 + * Creates an input modalias out of preset environmental variables.
1041 + *
1042 + * @1 Pointer to where modalias will be created
1043 + * @2 Maximum size of the modalias
1044 + *
1045 + * Returns: 0 if success, -1 otherwise
1046 + */
1047  int get_input_modalias(char *modalias, int modalias_len) {
1048         char *product_env;
1049         char *ptr;
1050 @@ -245,6 +221,14 @@
1051  #undef NBITS
1052  #undef TEST_INPUT_BIT
1053  
1054 +/**
1055 + * Creates a PCI modalias out of preset environmental variables.
1056 + *
1057 + * @1 Pointer to where modalias will be created
1058 + * @2 Maximum size of the modalias
1059 + *
1060 + * Returns: 0 if success, -1 otherwise
1061 + */
1062  int get_pci_modalias(char *modalias, int modalias_len) {
1063         char *class_env, *id_env, *subsys_env;
1064         char *ptr;
1065 @@ -290,6 +274,15 @@
1066         return 0;
1067  }
1068  
1069 +/**
1070 + * Creates an IEEE1394 (FireWire) modalias out of preset environmental
1071 + * variables.
1072 + *
1073 + * @1 Pointer to where modalias will be created
1074 + * @2 Maximum size of the modalias
1075 + *
1076 + * Returns: 0 if success, -1 otherwise
1077 + */
1078  int get_ieee1394_modalias(char *modalias, int modalias_len) {
1079         char *vendor_env, *model_env;
1080         char *specifier_env, *version_env;
1081 @@ -317,6 +310,14 @@
1082         return 0;
1083  }
1084  
1085 +/**
1086 + * Creates a serio modalias out of preset environmental variables.
1087 + *
1088 + * @1 Pointer to where modalias will be created
1089 + * @2 Maximum size of the modalias
1090 + *
1091 + * Returns: 0 if success, -1 otherwise
1092 + */
1093  int get_serio_modalias(char *modalias, int modalias_len) {
1094         char *serio_type_env, *serio_proto_env;
1095         char *serio_id_env, *serio_extra_env;
1096 @@ -344,6 +345,14 @@
1097         return 0;
1098  }
1099  
1100 +/**
1101 + * Creates an USB modalias out of preset environmental variables.
1102 + *
1103 + * @1 Pointer to where modalias will be created
1104 + * @2 Maximum size of the modalias
1105 + *
1106 + * Returns: 0 if success, -1 otherwise
1107 + */
1108  int get_usb_modalias(char *modalias, int modalias_len) {
1109         char *product_env, *type_env, *interface_env;
1110         char *ptr;
1111 @@ -409,6 +418,16 @@
1112         return 0;
1113  }
1114  
1115 +/**
1116 + * Distributes modalias generating according to the bus name.
1117 + *
1118 + * @1 Bus name
1119 + * @2 Pointer to where modalias will be created
1120 + * @3 Maximum size of the modalias
1121 + *
1122 + * Returns: The return value of the subsystem modalias function, or -1 if
1123 + * no match.
1124 + */
1125  int get_modalias(char *bus, char *modalias, int modalias_len) {
1126         memset(modalias, 0, modalias_len);
1127         
1128 @@ -435,6 +454,16 @@
1129         return -1;
1130  }
1131  
1132 +/**
1133 + * Turns all environmental variables as set when invoked by /proc/sys/hotplug
1134 + * into an uevent formatted (thus not null-terminated) string.
1135 + *
1136 + * @1 All environmental variables
1137 + * @2 Bus of the event (as read from argv)
1138 + * @3 Pointer to size of the returned uevent string
1139 + *
1140 + * Returns: Not null terminated uevent string.
1141 + */
1142  inline char *get_uevent_string(char **environ, char *bus, unsigned long *uevent_string_len) {
1143         char *uevent_string;
1144         char *tmp;
1145 @@ -516,7 +545,7 @@
1146                 return 1;
1147         }
1148         
1149 -       netlink_socket = init_netlink_socket();
1150 +       netlink_socket = init_netlink_socket(NETLINK_CONNECT);
1151         if (netlink_socket == -1) {
1152                 ERROR("netlink init","Unable to open netlink socket.");
1153                 goto exit;
1154 diff -urN -x .svn hotplug2-0.9/hotplug2.h hotplug2/hotplug2.h
1155 --- hotplug2-0.9/hotplug2.h     2006-10-08 12:21:56.000000000 +0200
1156 +++ hotplug2/hotplug2.h 2007-07-09 01:17:14.865503750 +0200
1157 @@ -34,7 +34,7 @@
1158  #endif
1159  
1160  #ifndef O_NOATIME
1161 -#define O_NOATIME                                      01000000
1162 +#define O_NOATIME                      01000000
1163  #endif
1164  
1165  #define ERROR(action, fmt, arg...)     fprintf(stderr, "[%s]: " fmt"\n", action, ##arg);
1166 @@ -47,7 +47,7 @@
1167  
1168  #define UEVENT_BUFFER_SIZE             2048
1169  #define HOTPLUG2_POLL_INTERVAL         20000
1170 -#define HOTPLUG2_THROTTLE_INTERVAL             10000
1171 +#define HOTPLUG2_THROTTLE_INTERVAL     10000
1172  #define HOTPLUG2_RULE_PATH             "/etc/hotplug2.rules"
1173  
1174  #define ACTION_ADD                     0
1175 diff -urN -x .svn hotplug2-0.9/hotplug2_utils.c hotplug2/hotplug2_utils.c
1176 --- hotplug2-0.9/hotplug2_utils.c       1970-01-01 01:00:00.000000000 +0100
1177 +++ hotplug2/hotplug2_utils.c   2007-07-09 01:17:14.869504000 +0200
1178 @@ -0,0 +1,96 @@
1179 +#include <stdio.h>
1180 +#include <string.h>
1181 +#include <stdlib.h>
1182 +#include <fcntl.h>
1183 +#include <stdio.h>
1184 +#include <unistd.h>
1185 +#include <errno.h>
1186 +#include <sys/socket.h>
1187 +#include <sys/types.h>
1188 +#include <sys/un.h>
1189 +#include <sys/wait.h>
1190 +#include <linux/types.h>
1191 +#include <linux/netlink.h>
1192 +
1193 +#include "hotplug2_utils.h"
1194 +
1195 +/**
1196 + * A trivial function that reads kernel seqnum from sysfs.
1197 + *
1198 + * Returns: Seqnum as read from sysfs
1199 + */
1200 +inline event_seqnum_t get_kernel_seqnum() {
1201 +       FILE *fp;
1202 +       
1203 +       char filename[64];
1204 +       char seqnum[64];
1205 +       
1206 +       strcpy(filename, sysfs_seqnum_path);
1207 +       
1208 +       fp = fopen(filename, "r");
1209 +       if (fp == NULL)
1210 +               return 0;
1211 +       
1212 +       fread(seqnum, 1, 64, fp);
1213 +       fclose(fp);
1214 +       
1215 +       return strtoull(seqnum, NULL, 0);
1216 +}
1217 +
1218 +/**
1219 + * Opens a PF_NETLINK socket into the kernel, to read uevents.
1220 + *
1221 + * @1 Specifies type of socket (whether we bind or whether we connect) 
1222 + *
1223 + * Returns: Socket fd if succesful, -1 otherwise.
1224 + */
1225 +inline int init_netlink_socket(int type) {
1226 +       int netlink_socket;
1227 +       struct sockaddr_nl snl;
1228 +       int buffersize = 16 * 1024 * 1024;
1229 +       
1230 +       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
1231 +       snl.nl_family = AF_NETLINK;
1232 +       snl.nl_pid = getpid();
1233 +       snl.nl_groups = 1;
1234 +       netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
1235 +       if (netlink_socket == -1) {
1236 +               ERROR("opening netlink","Failed socket: %s.", strerror(errno));
1237 +               return -1;
1238 +       }
1239 +       
1240 +       /*
1241 +        * We're trying to override buffer size. If we fail, we attempt to set a big buffer and pray.
1242 +        */
1243 +       if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize))) {
1244 +               ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
1245 +               
1246 +               /* Somewhat safe default. */
1247 +               buffersize = 106496;
1248 +               
1249 +               if (setsockopt(netlink_socket, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize))) {
1250 +                       ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
1251 +               }
1252 +       }
1253 +       
1254 +       /*
1255 +        * hotplug2-dnode performs connect, while hotplug2 daemon binds
1256 +        */
1257 +       switch (type) {
1258 +               case NETLINK_CONNECT:
1259 +                       if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
1260 +                               ERROR("opening netlink","Failed connect: %s.", strerror(errno));
1261 +                               close(netlink_socket);
1262 +                               return -1;
1263 +                       }
1264 +                       
1265 +               default:
1266 +                       if (bind(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
1267 +                               ERROR("opening netlink","Failed bind: %s.", strerror(errno));
1268 +                               close(netlink_socket);
1269 +                               return -1;
1270 +                       }
1271 +       }
1272 +       
1273 +       return netlink_socket;
1274 +}
1275 diff -urN -x .svn hotplug2-0.9/hotplug2_utils.h hotplug2/hotplug2_utils.h
1276 --- hotplug2-0.9/hotplug2_utils.h       1970-01-01 01:00:00.000000000 +0100
1277 +++ hotplug2/hotplug2_utils.h   2007-07-09 01:17:14.869504000 +0200
1278 @@ -0,0 +1,21 @@
1279 +/*****************************************************************************\
1280 +*  _  _       _          _              ___                                   *
1281 +* | || | ___ | |_  _ __ | | _  _  __ _ |_  )                                  *
1282 +* | __ |/ _ \|  _|| '_ \| || || |/ _` | / /                                   *
1283 +* |_||_|\___/ \__|| .__/|_| \_,_|\__, |/___|                                  *
1284 +*                 |_|            |___/                                        *
1285 +\*****************************************************************************/
1286 +
1287 +#ifndef HOTPLUG2_UTILS_H
1288 +#define HOTPLUG2_UTILS_H 1
1289 +
1290 +#include "hotplug2.h"
1291 +
1292 +#define NETLINK_UNDEFINED      0
1293 +#define NETLINK_CONNECT                1
1294 +#define NETLINK_BIND           2
1295 +
1296 +inline event_seqnum_t get_kernel_seqnum();
1297 +inline int init_netlink_socket(int);
1298 +
1299 +#endif
1300 diff -urN -x .svn hotplug2-0.9/linux24_compat/hotplug2-coldplug-2.4.c hotplug2/linux24_compat/hotplug2-coldplug-2.4.c
1301 --- hotplug2-0.9/linux24_compat/hotplug2-coldplug-2.4.c 2006-09-25 22:22:47.000000000 +0200
1302 +++ hotplug2/linux24_compat/hotplug2-coldplug-2.4.c     2007-07-09 01:17:14.793499250 +0200
1303 @@ -28,59 +28,7 @@
1304  #include "../mem_utils.h"
1305  #include "../parser_utils.h"
1306  #include "../filemap_utils.h"
1307 -
1308 -inline int init_netlink_socket() {
1309 -       int netlink_socket;
1310 -       struct sockaddr_nl snl;
1311 -       int buffersize = 16 * 1024 * 1024;
1312 -       
1313 -       memset(&snl, 0x00, sizeof(struct sockaddr_nl));
1314 -       snl.nl_family = AF_NETLINK;
1315 -       snl.nl_pid = getpid();
1316 -       snl.nl_groups = 1;
1317 -       netlink_socket = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
1318 -       if (netlink_socket == -1) {
1319 -               ERROR("opening netlink","Failed socket: %s.", strerror(errno));
1320 -               return -1;
1321 -       }
1322 -       
1323 -       if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUFFORCE, &buffersize, sizeof(buffersize))) {
1324 -               ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno));
1325 -               
1326 -               /* Somewhat safe default. */
1327 -               buffersize = 106496;
1328 -               
1329 -               if (setsockopt(netlink_socket, SOL_SOCKET, SO_SNDBUF, &buffersize, sizeof(buffersize))) {
1330 -                       ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno));
1331 -               }
1332 -       }
1333 -       
1334 -       if (connect(netlink_socket, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl))) {
1335 -               ERROR("opening netlink","Failed bind: %s.", strerror(errno));
1336 -               close(netlink_socket);
1337 -               return -1;
1338 -       }
1339 -       
1340 -       return netlink_socket;
1341 -}
1342 -
1343 -inline event_seqnum_t get_kernel_seqnum() {
1344 -       FILE *fp;
1345 -       
1346 -       char filename[64];
1347 -       char seqnum[64];
1348 -       
1349 -       strcpy(filename, sysfs_seqnum_path);
1350 -       
1351 -       fp = fopen(filename, "r");
1352 -       if (fp == NULL)
1353 -               return 0;
1354 -       
1355 -       fread(seqnum, 1, 64, fp);
1356 -       fclose(fp);
1357 -       
1358 -       return strtoull(seqnum, NULL, 0);
1359 -}
1360 +#include "../hotplug2_utils.h"
1361  
1362  inline char *get_uevent_string(char **environ, unsigned long *uevent_string_len) {
1363         char *uevent_string;
1364 @@ -413,7 +361,7 @@
1365  int main(int argc, char *argv[], char **environ) {
1366         int netlink_socket;
1367         
1368 -       netlink_socket = init_netlink_socket();
1369 +       netlink_socket = init_netlink_socket(NETLINK_CONNECT);
1370         if (netlink_socket == -1) {
1371                 ERROR("netlink init","Unable to open netlink socket.");
1372                 return 1;
1373 diff -urN -x .svn hotplug2-0.9/linux24_compat/hotplug2-modwrap.c hotplug2/linux24_compat/hotplug2-modwrap.c
1374 --- hotplug2-0.9/linux24_compat/hotplug2-modwrap.c      2006-09-25 22:23:07.000000000 +0200
1375 +++ hotplug2/linux24_compat/hotplug2-modwrap.c  2007-07-09 01:17:14.789499000 +0200
1376 @@ -30,8 +30,19 @@
1377  #include "../parser_utils.h"
1378  #include "../filemap_utils.h"
1379  
1380 +#define MODULES_PATH           "/lib/modules/"
1381 +#define MODULES_ALIAS          "modules.alias"
1382 +
1383 +/**
1384 + * A simple fork/exec wrapper
1385 + *
1386 + * @1 Complete argv, including app path
1387 + *
1388 + * Returns: -1 if error, children return value otherwise
1389 + */
1390  int execute(char **argv) {
1391         pid_t p;
1392 +       int status;
1393         
1394         p = fork();
1395         switch (p) {
1396 @@ -42,10 +53,11 @@
1397                         exit(1);
1398                         break;
1399                 default:
1400 -                       waitpid(p, NULL, 0);
1401 +                       waitpid(p, &status, 0);
1402                         break;
1403         }
1404 -       return 0;
1405 +
1406 +       return WEXITSTATUS(status);
1407  }
1408  
1409  int main(int argc, char *argv[]) {
1410 @@ -63,21 +75,36 @@
1411         
1412         match_alias = strdup(argv[argc - 1]);
1413         
1414 +       /*
1415 +        * If we can't do uname, we're absolutely screwed and there's no
1416 +        * sense thinking twice about anything.
1417 +        */
1418         if (uname(&unamebuf)) {
1419                 ERROR("uname", "Unable to perform uname: %s.", strerror(errno));
1420                 return 1;
1421         }
1422         
1423 -       /* We use this one */
1424 +       /*
1425 +        * We allow setting the modprobe command to an arbitrary value.
1426 +        *
1427 +        * The whole trick lies in executing modprobe with exactly the
1428 +        * same argv as this app was executed, except we use a different
1429 +        * argv[0] (application path) and argv[argc-1] (we substitute
1430 +        * the given modalias by the matching module name)
1431 +        */
1432         argv[0] = getenv("MODPROBE_COMMAND");
1433         if (argv[0] == NULL)
1434                 argv[0] = "/sbin/modprobe";
1435 -       
1436 -       /* "/lib/modules/" + "/" + "\0" */
1437 -       filename = xmalloc(15 + strlen(unamebuf.release) + strlen("modules.alias"));
1438 -       strcpy(filename, "/lib/modules/");
1439 +
1440 +       /*
1441 +        * Compose a path, /lib/modules/`uname -r`/modules.alias
1442 +        *
1443 +        * "/lib/modules/" + "/" + "\0" 
1444 +        */
1445 +       filename = xmalloc(strlen(MODULES_PATH) + strlen(unamebuf.release) + strlen(MODULES_ALIAS));
1446 +       strcpy(filename, MODULES_PATH);
1447         strcat(filename, unamebuf.release);
1448 -       strcat(filename, "/modules.alias");
1449 +       strcat(filename, MODULES_ALIAS);
1450         
1451         if (map_file(filename, &aliasmap)) {
1452                 ERROR("map_file", "Unable to map file: `%s'.", filename);
1453 @@ -86,10 +113,16 @@
1454                 return 1;
1455         }
1456         
1457 +       /*
1458 +        * Read all the aliases, match them against given parameter.
1459 +        */
1460         nptr = aliasmap.map;
1461         while ((line = dup_line(nptr, &nptr)) != NULL) {
1462                 nline = line;
1463                 
1464 +               /*
1465 +                * We want aliases only
1466 +                */
1467                 token = dup_token(nline, &nline, isspace);
1468                 if (!token || strcmp(token, "alias")) {
1469                         free(token);
1470 @@ -98,12 +131,18 @@
1471                 }
1472                 free(token);
1473                 
1474 +               /*
1475 +                * It's an alias, so fetch it
1476 +                */
1477                 cur_alias = dup_token(nline, &nline, isspace);
1478                 if (!cur_alias) {
1479                         free(line);
1480                         continue;
1481                 }
1482                 
1483 +               /*
1484 +                * And now we get the module name
1485 +                */
1486                 module = dup_token(nline, &nline, isspace);
1487                 if (!module) {
1488                         free(line);
1489 @@ -111,10 +150,14 @@
1490                         continue;
1491                 }
1492                 
1493 +               /*
1494 +                * If we match, we do the modalias->module name
1495 +                * substitution as described above and execute.
1496 +                */
1497                 if (!fnmatch(cur_alias, match_alias, 0)) {
1498                         argv[argc - 1] = module;
1499                         if (execute(argv)) {
1500 -                               ERROR("execute", "Unable to execute: `%s'.", argv[0]);
1501 +                               ERROR("execute", "Error during exection of: `%s'.", argv[0]);
1502                         }
1503                 }
1504                 
1505 @@ -122,6 +165,17 @@
1506                 free(module);
1507                 free(line);
1508         }
1509 +
1510 +       /*
1511 +        * Perhaps we didn't match anything, so we might've been given
1512 +        * a module name instead of a modalias. Try to modprobe it
1513 +        * right away.
1514 +        */
1515 +       if (strcmp(argv[argc - 1], match_alias) == 0) {
1516 +               if (execute(argv)) {
1517 +                       ERROR("execute", "Error during exection of: `%s'.", argv[0]);
1518 +               }
1519 +       }       
1520         
1521         free(filename);
1522         free(match_alias);
1523 diff -urN -x .svn hotplug2-0.9/linux24_compat/Makefile hotplug2/linux24_compat/Makefile
1524 --- hotplug2-0.9/linux24_compat/Makefile        2006-09-26 00:26:46.000000000 +0200
1525 +++ hotplug2/linux24_compat/Makefile    2007-07-09 01:17:14.793499250 +0200
1526 @@ -2,16 +2,17 @@
1527  
1528  BINS=generate_alias hotplug2-coldplug-2.4 hotplug2-modwrap
1529  SUBDIRS=
1530 +DESTDIR=
1531  
1532  
1533  all: $(BINS)
1534  
1535  install:
1536 -       $(INSTALL_BIN) hotplug2-coldplug-2.4 hotplug2-modwrap /sbin/
1537 -       $(INSTALL_BIN) generate_alias /usr/sbin/
1538 +       $(INSTALL_BIN) hotplug2-coldplug-2.4 hotplug2-modwrap $(DESTDIR)/sbin/
1539 +       $(INSTALL_BIN) generate_alias $(DESTDIR)/usr/sbin/
1540  
1541  
1542 -hotplug2-coldplug-2.4: hotplug2-coldplug-2.4.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
1543 +hotplug2-coldplug-2.4: hotplug2-coldplug-2.4.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o ../hotplug2_utils.o
1544  hotplug2-modwrap: hotplug2-modwrap.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
1545  generate_alias: generate_alias.o ../parser_utils.o ../filemap_utils.o ../mem_utils.o
1546  
1547 diff -urN -x .svn hotplug2-0.9/Makefile hotplug2/Makefile
1548 --- hotplug2-0.9/Makefile       2006-09-26 01:03:08.000000000 +0200
1549 +++ hotplug2/Makefile   2007-07-09 01:17:14.869504000 +0200
1550 @@ -2,16 +2,17 @@
1551  
1552  BINS=hotplug2 hotplug2-dnode
1553  SUBDIRS=linux24_compat docs examples
1554 +DESTDIR=
1555  
1556  
1557  all: $(BINS)
1558  
1559  install:
1560 -       $(INSTALL_BIN) $(BINS) /sbin/
1561 +       $(INSTALL_BIN) $(BINS) $(DESTDIR)/sbin/
1562  
1563  
1564 -hotplug2: hotplug2.o childlist.o mem_utils.o rules.o
1565 -hotplug2-dnode: hotplug2-dnode.o mem_utils.o parser_utils.o
1566 +hotplug2: hotplug2.o hotplug2_utils.o childlist.o mem_utils.o rules.o filemap_utils.o
1567 +hotplug2-dnode: hotplug2-dnode.o hotplug2_utils.o mem_utils.o parser_utils.o
1568  
1569  
1570  include common.mak
1571 diff -urN -x .svn hotplug2-0.9/mem_utils.c hotplug2/mem_utils.c
1572 --- hotplug2-0.9/mem_utils.c    2006-09-25 22:21:45.000000000 +0200
1573 +++ hotplug2/mem_utils.c        2007-07-09 01:17:14.865503750 +0200
1574 @@ -9,6 +9,13 @@
1575  #include <stdlib.h>
1576  #include <stdio.h>
1577  
1578 +/**
1579 + * A malloc wrapper. Exits if no memory.
1580 + *
1581 + * @1 Ammount of memory to allocate
1582 + *
1583 + * Returns: Pointer to freshly allocated memory
1584 + */
1585  inline void *xmalloc(size_t size) {
1586         void *ptr;
1587         ptr = malloc(size);
1588 @@ -19,6 +26,14 @@
1589         return ptr;
1590  }
1591  
1592 +/**
1593 + * A realloc wrapper. Exits if no memory.
1594 + *
1595 + * @1 Old pointer
1596 + * @2 Ammount of memory to allocate
1597 + *
1598 + * Returns: Pointer to reallocated memory
1599 + */
1600  inline void *xrealloc(void *inptr, size_t size) {
1601         void *ptr;
1602         ptr = realloc(inptr, size);
1603 diff -urN -x .svn hotplug2-0.9/parser_utils.c hotplug2/parser_utils.c
1604 --- hotplug2-0.9/parser_utils.c 2006-09-25 22:21:13.000000000 +0200
1605 +++ hotplug2/parser_utils.c     2007-07-09 01:17:14.865503750 +0200
1606 @@ -12,6 +12,16 @@
1607  #include "mem_utils.h"
1608  #include "parser_utils.h"
1609  
1610 +/**
1611 + * Creates a newly allocated null-terminated string representing line
1612 + * starting at a given pointer and ending at the closest newline. If
1613 + * no newline present, returns NULL. TODO, use dup_token
1614 + *
1615 + * @1 Starting pointer
1616 + * @2 Pointer where the end position is returned
1617 + *
1618 + * Returns: Newly allocated string containing the line or NULL
1619 + */
1620  char *dup_line(char *start, char **nptr) {
1621         char *ptr, *rv;
1622         
1623 @@ -29,6 +39,15 @@
1624         return rv;
1625  }
1626  
1627 +/**
1628 + * Returns a token delimited by the given function.
1629 + *
1630 + * @1 Starting pointer
1631 + * @2 Pointer where the end position is returned
1632 + * @3 Function that identifies the delimiter characters
1633 + *
1634 + * Returns: Newly allocated string containing the token or NULL
1635 + */
1636  char *dup_token(char *start, char **nptr, int (*isdelimiter)(int)) {
1637         char *ptr, *rv;
1638         
1639 @@ -56,6 +75,16 @@
1640         return rv;
1641  }
1642  
1643 +/**
1644 + * Returns the last token delimited by the given function.
1645 + *
1646 + * @1 Starting pointer of the whole string
1647 + * @2 Starting position
1648 + * @3 Pointer where the end position is returned
1649 + * @4 Function that identifies the delimiter characters
1650 + *
1651 + * Returns: Newly allocated string containing the token or NULL
1652 + */
1653  char *dup_token_r(char *start, char *start_string, char **nptr, int (*isdelimiter)(int)) {
1654         char *ptr, *rv;
1655         
1656 diff -urN -x .svn hotplug2-0.9/rules.c hotplug2/rules.c
1657 --- hotplug2-0.9/rules.c        2006-09-29 22:19:31.000000000 +0200
1658 +++ hotplug2/rules.c    2007-07-09 02:01:10.962249500 +0200
1659 @@ -22,11 +22,18 @@
1660  #include <sys/stat.h>
1661  
1662  #include "mem_utils.h"
1663 +#include "filemap_utils.h"
1664  #include "hotplug2.h"
1665  #include "rules.h"
1666  
1667 -#define last_rule return_rules->rules[return_rules->rules_c - 1]
1668  
1669 +/**
1670 + * Function supplementing 'mkdir -p'.
1671 + *
1672 + * @1 Path to be mkdir'd
1673 + *
1674 + * Returns: void
1675 + */
1676  static void mkdir_p(char *path) {
1677         char *ptr;
1678         struct stat statbuf;
1679 @@ -59,6 +66,40 @@
1680         free(path);
1681  }
1682  
1683 +/**
1684 + * Function supplementing 'rmdir -p'.
1685 + *
1686 + * @1 Path to be rmdir'd
1687 + *
1688 + * Returns: void
1689 + */
1690 +static void rmdir_p(char *path) {
1691 +       char *ptr;
1692 +       
1693 +       path = strdup(path);
1694 +       ptr = path;
1695 +       while (ptr != NULL) {
1696 +               ptr = strrchr(path, '/');
1697 +               if (ptr == NULL)
1698 +                       break;
1699 +               
1700 +               *ptr = '\0';
1701 +               
1702 +               if (rmdir(path))
1703 +                       break;
1704 +       }
1705 +       free(path);
1706 +}
1707 +
1708 +/**
1709 + * Replaces all needles by a given value.
1710 + *
1711 + * @1 Haystack (which gets free'd in the function)
1712 + * @2 Needle
1713 + * @3 Needle replacement
1714 + *
1715 + * Returns: Newly allocated haysteck after replacement.
1716 + */
1717  static char *replace_str(char *hay, char *needle, char *replacement) {
1718          char *ptr, *start, *bptr, *buf;
1719          int occurences, j;
1720 @@ -128,7 +169,15 @@
1721          return buf;
1722  }
1723  
1724 -inline int isescaped(char *hay, char *ptr) {
1725 +/**
1726 + * Trivial utility, figuring out whether a character is escaped or not.
1727 + *
1728 + * @1 Haystack
1729 + * @2 Pointer to the character in question
1730 + *
1731 + * Returns: 1 if escaped, 0 otherwise
1732 + */
1733 +static inline int isescaped(char *hay, char *ptr) {
1734         if (ptr <= hay)
1735                 return 0;
1736         
1737 @@ -138,6 +187,15 @@
1738         return 1;
1739  }
1740  
1741 +/**
1742 + * Performs replacement of all keys by their value based on the hotplug
1743 + * event structure. Keys are identified as strings %KEY%.
1744 + *
1745 + * @1 Haystack
1746 + * @2 Hotplug event structure
1747 + *
1748 + * Returns: Newly allocated haystack (old is freed)
1749 + */
1750  static char *replace_key_by_value(char *hay, struct hotplug2_event_t *event) {
1751         char *sptr = hay, *ptr = hay;
1752         char *buf, *replacement;
1753 @@ -171,6 +229,17 @@
1754         return hay;
1755  }
1756  
1757 +/**
1758 + * Obtains all information from hotplug event structure about a device node.
1759 + * Creates the device node at a given path (expandable by keys) and with
1760 + * given mode.
1761 + *
1762 + * @1 Hotplug event structure
1763 + * @2 Path (may contain keys)
1764 + * @3 Mode of the file
1765 + *
1766 + * Returns: 0 if success, non-zero otherwise
1767 + */
1768  static int make_dev_from_event(struct hotplug2_event_t *event, char *path, mode_t devmode) {
1769         char *subsystem, *major, *minor, *devpath;
1770         int rv = 1;
1771 @@ -196,12 +265,27 @@
1772         path = replace_key_by_value(path, event);
1773         mkdir_p(path);
1774         rv = mknod(path, devmode, makedev(atoi(major), atoi(minor)));
1775 +
1776 +       /*
1777 +        * Fixes an issue caused by devmode being modified by umask.
1778 +        */
1779 +       chmod(path, devmode);
1780 +
1781         free(path);
1782         
1783  return_value:
1784         return rv;
1785  }
1786  
1787 +/**
1788 + * Execute an application without invoking a shell.
1789 + *
1790 + * @1 Hotplug event structure
1791 + * @2 Path to the application, with expandable keys
1792 + * @3 Argv for the application, with expandable keys
1793 + *
1794 + * Returns: Exit status of the application.
1795 + */
1796  static int exec_noshell(struct hotplug2_event_t *event, char *application, char **argv) {
1797         pid_t p;
1798         int i, status;
1799 @@ -211,11 +295,12 @@
1800                 case -1:
1801                         return -1;
1802                 case 0:
1803 +                       application = replace_key_by_value(strdup(application), event);
1804                         for (i = 0; argv[i] != NULL; i++) {
1805                                 argv[i] = replace_key_by_value(argv[i], event);
1806                         }
1807                         execvp(application, argv);
1808 -                       exit(0);
1809 +                       exit(127);
1810                         break;
1811                 default:
1812                         if (waitpid(p, &status, 0) == -1)
1813 @@ -226,6 +311,14 @@
1814         }
1815  }
1816  
1817 +/**
1818 + * Execute an application while invoking a shell.
1819 + *
1820 + * @1 Hotplug event structure
1821 + * @2 The application and all its arguments, with expandable keys
1822 + *
1823 + * Returns: Exit status of the application.
1824 + */
1825  static int exec_shell(struct hotplug2_event_t *event, char *application) {
1826         int rv;
1827         
1828 @@ -235,6 +328,15 @@
1829         return rv;
1830  }
1831  
1832 +/**
1833 + * Create a symlink, with necessary parent directories.
1834 + *
1835 + * @1 Hotplug event structure
1836 + * @2 Link target, with expandable keys
1837 + * @3 Link name, with expandable keys
1838 + *
1839 + * Returns: return value of symlink()
1840 + */
1841  static int make_symlink(struct hotplug2_event_t *event, char *target, char *linkname) {
1842         int rv;
1843         
1844 @@ -250,11 +352,50 @@
1845         return rv;
1846  }
1847  
1848 -static int chown_chgrp(int action, char *file, char *param) {
1849 +/**
1850 + * Chmod a given file.
1851 + *
1852 + * @1 Hotplug event structure
1853 + * @2 File name, with expandable keys
1854 + * @3 Chmod value, with expandable keys
1855 + *
1856 + * Returns: return value of chmod()
1857 + */
1858 +static int chmod_file(struct hotplug2_event_t *event, char *file, char *value) {
1859 +       int rv;
1860 +
1861 +       file = replace_key_by_value(strdup(file), event);
1862 +       value = replace_key_by_value(strdup(value), event);
1863 +
1864 +       rv = chmod(file, strtoul(value, 0, 8));
1865 +
1866 +       free(file);
1867 +       free(value);
1868 +
1869 +       return rv;
1870 +}
1871 +
1872 +
1873 +/**
1874 + * Change owner or group of a given file.
1875 + *
1876 + * @1 Hotplug event structure
1877 + * @2 Whether we chown or chgrp
1878 + * @3 Filename, with expandable keys
1879 + * @4 Group or user name, with expandable keys
1880 + *
1881 + * Returns: return value of chown()
1882 + */
1883 +static int chown_chgrp(struct hotplug2_event_t *event, int action, char *file, char *param) {
1884         struct group *grp;
1885         struct passwd *pwd;
1886         int rv;
1887 -       
1888 +
1889 +       file = replace_key_by_value(strdup(file), event);
1890 +       param = replace_key_by_value(strdup(param), event);
1891 +
1892 +       rv = -1;
1893 +
1894         switch (action) {
1895                 case ACT_CHOWN:
1896                         pwd = getpwnam(param);
1897 @@ -265,11 +406,37 @@
1898                         rv = chown(file, -1, grp->gr_gid);
1899                         break;
1900         }
1901 +
1902 +       free(file);
1903 +       free(param);
1904         
1905 -       return -1;
1906 +       return rv;
1907 +}
1908 +
1909 +/**
1910 + * Prints all uevent keys.
1911 + *
1912 + * @1 Hotplug event structure
1913 + *
1914 + * Returns: void
1915 + */
1916 +static void print_debug(struct hotplug2_event_t *event) {
1917 +       int i;
1918 +
1919 +       for (i = 0; i < event->env_vars_c; i++)
1920 +               printf("%s=%s\n", event->env_vars[i].key, event->env_vars[i].value);
1921  }
1922  
1923 -static int rule_condition_eval(struct hotplug2_event_t *event, struct condition_t *condition) {
1924 +/**
1925 + * Evaluates a condition according to a given hotplug event structure.
1926 + *
1927 + * @1 Hotplug event structure
1928 + * @2 Condition to be evaluated
1929 + *
1930 + * Returns: 1 if match, 0 if no match, EVAL_NOT_AVAILABLE if unable to
1931 + * perform evaluation
1932 + */
1933 +int rule_condition_eval(struct hotplug2_event_t *event, struct condition_t *condition) {
1934         int rv;
1935         char *event_value = NULL;
1936         regex_t preg;
1937 @@ -314,6 +481,16 @@
1938         return EVAL_NOT_AVAILABLE;
1939  }
1940  
1941 +/**
1942 + * Executes a rule. Contains evaluation of all conditions prior
1943 + * to execution.
1944 + *
1945 + * @1 Hotplug event structure
1946 + * @2 The rule to be executed
1947 + *
1948 + * Returns: 0 if success, -1 if the whole event is to be 
1949 + * discared, 1 if bail out of this particular rule was required
1950 + */
1951  int rule_execute(struct hotplug2_event_t *event, struct rule_t *rule) {
1952         int i, last_rv;
1953         
1954 @@ -347,11 +524,11 @@
1955                                 last_rv = make_dev_from_event(event, rule->actions[i].parameter[0], strtoul(rule->actions[i].parameter[1], NULL, 0));
1956                                 break;
1957                         case ACT_CHMOD:
1958 -                               last_rv = chmod(rule->actions[i].parameter[0], strtoul(rule->actions[i].parameter[1], NULL, 0));
1959 +                               last_rv = chmod_file(event, rule->actions[i].parameter[0], rule->actions[i].parameter[1]);
1960                                 break;
1961                         case ACT_CHOWN:
1962                         case ACT_CHGRP:
1963 -                               last_rv = chown_chgrp(rule->actions[i].type, rule->actions[i].parameter[0], rule->actions[i].parameter[1]);
1964 +                               last_rv = chown_chgrp(event, rule->actions[i].type, rule->actions[i].parameter[0], rule->actions[i].parameter[1]);
1965                                 break;
1966                         case ACT_SYMLINK:
1967                                 last_rv = make_symlink(event, rule->actions[i].parameter[0], rule->actions[i].parameter[1]);
1968 @@ -365,12 +542,49 @@
1969                         case ACT_SETENV:
1970                                 last_rv = setenv(rule->actions[i].parameter[0], rule->actions[i].parameter[1], 1);
1971                                 break;
1972 +                       case ACT_REMOVE:
1973 +                               last_rv = unlink(rule->actions[i].parameter[0]);
1974 +                               rmdir_p(rule->actions[i].parameter[0]);
1975 +                               break;
1976 +                       case ACT_DEBUG:
1977 +                               print_debug(event);
1978 +                               last_rv = 0;
1979 +                               break;
1980                 }
1981         }
1982         
1983         return 0;
1984  }
1985  
1986 +/**
1987 + * Sets the flags of the given rule.
1988 + *
1989 + * @1 Rule structure
1990 + *
1991 + * Returns: void
1992 + */
1993 +void rule_flags(struct rule_t *rule) {
1994 +       int i;
1995 +
1996 +       for (i = 0; i < rule->actions_c; i++) {
1997 +               switch (rule->actions[i].type) {
1998 +                       case ACT_FLAG_NOTHROTTLE:
1999 +                               rule->flags |= FLAG_NOTHROTTLE;
2000 +                               break;
2001 +               }
2002 +       }
2003 +       
2004 +       return;
2005 +}
2006 +
2007 +/**
2008 + * Checks whether the given character should initiate
2009 + * further parsing.
2010 + *
2011 + * @1 Character to examine
2012 + *
2013 + * Returns: 1 if it should, 0 otherwise
2014 + */
2015  static inline int isinitiator(int c) {
2016         switch (c) {
2017                 case ',':
2018 @@ -383,6 +597,16 @@
2019         return 0;
2020  }
2021  
2022 +/**
2023 + * Appends a character to a buffer. Enlarges if necessary.
2024 + *
2025 + * @1 Pointer to the buffer
2026 + * @2 Pointer to buffer size
2027 + * @3 Pointer to last buffer character
2028 + * @4 Appended character
2029 + *
2030 + * Returns: void
2031 + */
2032  static inline void add_buffer(char **buf, int *blen, int *slen, char c) {
2033         if (*slen + 1 >= *blen) {
2034                 *blen = *blen + 64;
2035 @@ -394,6 +618,14 @@
2036         *slen += 1;
2037  }
2038  
2039 +/**
2040 + * Parses a string into a syntactically acceptable value.
2041 + *
2042 + * @1 Input string
2043 + * @2 Pointer to the new position
2044 + *
2045 + * Returns: Newly allocated string.
2046 + */
2047  static char *rules_get_value(char *input, char **nptr) {
2048         int quotes = QUOTES_NONE;
2049         char *ptr = input;
2050 @@ -471,6 +703,16 @@
2051         return buf;
2052  }
2053  
2054 +/**
2055 + * Releases all memory associated with the ruleset. TODO: Make
2056 + * the behavior same for all _free() functions, ie. either
2057 + * release the given pointer itself or keep it, but do it
2058 + * in all functions!
2059 + *
2060 + * @1 The ruleset to be freed
2061 + *
2062 + * Returns: void
2063 + */
2064  void rules_free(struct rules_t *rules) {
2065         int i, j, k;
2066         
2067 @@ -492,10 +734,53 @@
2068         free(rules->rules);
2069  }
2070  
2071 -struct rules_t *rules_from_config(char *input) {
2072 -       int status = STATUS_KEY, terminate;
2073 +/**
2074 + * Includes a rule file.
2075 + *
2076 + * @1 Filename
2077 + * @2 The ruleset structure
2078 + *
2079 + * Returns: 0 if success, -1 otherwise
2080 + */
2081 +int rules_include(const char *filename, struct rules_t **return_rules) {
2082 +       struct filemap_t filemap;
2083 +       struct rules_t *rules;
2084 +
2085 +       if (map_file(filename, &filemap)) {
2086 +               ERROR("rules parse","Unable to open/mmap rules file.");
2087 +               return -1;
2088 +       }
2089 +       
2090 +       rules = rules_from_config((char*)(filemap.map), *return_rules);
2091 +       if (rules == NULL) {
2092 +               ERROR("rules parse","Unable to parse rules file.");
2093 +               return -1;
2094 +       }
2095 +
2096 +       unmap_file(&filemap);
2097 +
2098 +       return 0;
2099 +}
2100 +
2101 +/**
2102 + * Parses an entire file of rules.
2103 + *
2104 + * @1 The whole file in memory or mmap'd
2105 + *
2106 + * Returns: A newly allocated ruleset.
2107 + */
2108 +struct rules_t *rules_from_config(char *input, struct rules_t *return_rules) {
2109 +       #define last_rule return_rules->rules[return_rules->rules_c - 1]
2110 +       int nested;
2111 +       int status;     
2112 +       int terminate;
2113         char *buf;
2114 -       struct rules_t *return_rules;
2115 +
2116 +       /*
2117 +        * TODO: cleanup
2118 +        *
2119 +        * BIIIG cleanup... Use callbacks for actions and for internal actions.
2120 +        */
2121         
2122         int i, j;
2123         struct key_rec_t conditions[] = {       /*NOTE: We never have parameters for conditions. */
2124 @@ -506,6 +791,7 @@
2125                 {"!~", 0, COND_NMATCH_RE},
2126                 {NULL, 0, -1}
2127         };
2128 +
2129         struct key_rec_t actions[] = {
2130                 /*one line / one command*/
2131                 {"run", 1, ACT_RUN_SHELL},
2132 @@ -518,6 +804,9 @@
2133                 {"chmod", 2, ACT_CHMOD},
2134                 {"chgrp", 2, ACT_CHGRP},
2135                 {"setenv", 2, ACT_SETENV},
2136 +               {"remove", 1, ACT_REMOVE},
2137 +               {"nothrottle", 0, ACT_FLAG_NOTHROTTLE},
2138 +               {"printdebug", 0, ACT_DEBUG},
2139                 /*symlink*/
2140                 {"symlink", 2, ACT_SYMLINK},
2141                 {"softlink", 2, ACT_SYMLINK},
2142 @@ -527,9 +816,19 @@
2143                 {NULL, 0, -1}
2144         };
2145  
2146 -       return_rules = xmalloc(sizeof(struct rules_t));
2147 -       return_rules->rules_c = 1;
2148 -       return_rules->rules = xmalloc(sizeof(struct rule_t) * return_rules->rules_c);
2149 +       /*
2150 +        * A little trick for inclusion.
2151 +        */
2152 +       if (return_rules == NULL) {
2153 +               return_rules = xmalloc(sizeof(struct rules_t));
2154 +               return_rules->rules_c = 1;
2155 +               return_rules->rules = xmalloc(sizeof(struct rule_t) * return_rules->rules_c);
2156 +               nested = 0;
2157 +       } else {
2158 +               nested = 1;
2159 +       }
2160 +
2161 +       status = STATUS_KEY;
2162         
2163         last_rule.actions = NULL;
2164         last_rule.actions_c = 0;
2165 @@ -549,9 +848,26 @@
2166                         /* Skip to next line */
2167                         while (*input != '\0' && *input != '\n')
2168                                 input++;
2169 +
2170 +                       free(buf);
2171 +                       continue;
2172 +               } else if (buf[0] == '$') {
2173 +                       buf++;
2174 +
2175 +                       /*
2176 +                        * Warning, hack ahead...
2177 +                        */
2178 +                       if (!strcmp("include", buf)) {
2179 +                               buf = rules_get_value(input, &input);
2180 +                               if (rules_include(buf, &return_rules)) {
2181 +                                       ERROR("rules_include", "Unable to include ruleset '%s'!", buf);
2182 +                               }
2183 +                       }
2184 +
2185 +                       free(buf);
2186                         continue;
2187                 }
2188 -               
2189 +
2190                 switch (status) {
2191                         case STATUS_KEY:
2192                                 last_rule.conditions_c++;
2193 @@ -684,8 +1000,14 @@
2194                 return_rules->rules_c--;
2195                 return return_rules;
2196         } else {
2197 -               rules_free(return_rules);
2198 -               free(return_rules);
2199 +               /*
2200 +                * We don't want to cleanup if we're nested.
2201 +                */
2202 +               if (!nested) {
2203 +                       rules_free(return_rules);
2204 +                       free(return_rules);
2205 +               }
2206 +
2207                 return NULL;
2208         }
2209  }
2210 diff -urN -x .svn hotplug2-0.9/rules.h hotplug2/rules.h
2211 --- hotplug2-0.9/rules.h        2006-09-25 13:42:22.000000000 +0200
2212 +++ hotplug2/rules.h    2007-07-09 02:01:10.962249500 +0200
2213 @@ -24,9 +24,12 @@
2214  #define ACT_CHGRP                      6       /* chgrp <...> */
2215  #define ACT_CHOWN                      7       /* chown <...> */
2216  #define ACT_SYMLINK                    8       /* symlink <...> */
2217 -#define ACT_NEXT_EVENT         9       /* next */
2218 +#define ACT_NEXT_EVENT                 9       /* next */
2219  #define ACT_NEXT_IF_FAILED             10      /* next_if_failed */
2220  #define ACT_SETENV                     11      /* setenv <...> */
2221 +#define ACT_REMOVE                     12      /* remove <...> */
2222 +#define ACT_DEBUG                      13      /* debug */
2223 +#define ACT_FLAG_NOTHROTTLE            14      /* sets 'nothrottle' flag */
2224  
2225  #define EVAL_MATCH                     1
2226  #define EVAL_NOT_MATCH                 0
2227 @@ -42,6 +45,10 @@
2228  #define STATUS_INITIATOR               3       /* ',' for next cond, '{' for block*/
2229  #define STATUS_ACTION                  4       /* viz ACT_* and '}' for end of block */
2230  
2231 +#define FLAG_UNSET                     0
2232 +#define FLAG_ALL                       0xffffffff
2233 +#define FLAG_NOTHROTTLE                        1       /* We want this rule to ignore max_children limit */
2234 +
2235  struct key_rec_t {
2236         char *key;
2237         int param;
2238 @@ -65,6 +72,8 @@
2239         
2240         struct action_t *actions;
2241         int actions_c;
2242 +
2243 +       unsigned int flags;
2244  };
2245  
2246  struct rules_t {
2247 @@ -72,8 +81,10 @@
2248         int rules_c;
2249  };
2250  
2251 +int rule_condition_eval(struct hotplug2_event_t *, struct condition_t *);
2252  int rule_execute(struct hotplug2_event_t *, struct rule_t *);
2253 +void rule_flags(struct rule_t *);
2254  void rules_free(struct rules_t *);
2255 -struct rules_t *rules_from_config(char *);
2256 +struct rules_t *rules_from_config(char *, struct rules_t *);
2257  
2258  #endif /* ifndef RULES_H*/
2259 Binary files hotplug2-0.9/.swp and hotplug2/.swp differ
2260 diff -urN -x .svn hotplug2-0.9/TODO hotplug2/TODO
2261 --- hotplug2-0.9/TODO   1970-01-01 01:00:00.000000000 +0100
2262 +++ hotplug2/TODO       2007-06-28 14:51:00.012934184 +0200
2263 @@ -0,0 +1 @@
2264 + - live rules update (via inotify)