hotplug2 update - include hotplug2-init.rules from hotplug2.rules, fix permissions...
[openwrt/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)