1 /*****************************************************************************\
3 * | || | ___ | |_ _ __ | | _ _ __ _ |_ ) *
4 * | __ |/ _ \| _|| '_ \| || || |/ _` | / / *
5 * |_||_|\___/ \__|| .__/|_| \_,_|\__, |/___| *
7 \*****************************************************************************/
16 #include <sys/socket.h>
17 #include <sys/types.h>
22 #include <linux/types.h>
23 #include <linux/netlink.h>
26 #include "mem_utils.h"
27 #include "filemap_utils.h"
29 #include "hotplug2_utils.h"
31 #include "childlist.h"
33 #define TERMCONDITION (persistent == 0 && \
34 coldplug_p == FORK_FINISHED && \
36 highest_seqnum == get_kernel_seqnum())
39 * These variables are accessed from throughout the code.
41 * TODO: Move this into a hotplug2_t-like variable.
43 event_seqnum_t highest_seqnum
= 0;
52 struct hotplug2_child_t
*child
;
55 char *modprobe_command
= NULL
;
58 * Release all memory associated with an uevent read from kernel. The given
59 * pointer is no longer valid, as it gets freed as well.
61 * @1 The event that is to be freed.
65 inline void free_hotplug2_event(struct hotplug2_event_t
*event
) {
68 for (i
= 0; i
< event
->env_vars_c
; i
++) {
69 free(event
->env_vars
[i
].key
);
70 free(event
->env_vars
[i
].value
);
72 free(event
->env_vars
);
78 * A trivial function determining the action that the uevent.
80 * @1 String containing the action name (null-terminated).
82 * Returns: Macro of the given action
84 inline int get_hotplug2_event_action(char *action
) {
85 if (!strcmp(action
, "add"))
88 if (!strcmp(action
, "remove"))
91 return ACTION_UNKNOWN
;
95 * Looks up a value according to the given key.
97 * @1 A hotplug event structure
100 * Returns: The value of the key or NULL if no such key found
102 char *get_hotplug2_value_by_key(struct hotplug2_event_t
*event
, char *key
) {
105 for (i
= 0; i
< event
->env_vars_c
; i
++) {
106 if (!strcmp(event
->env_vars
[i
].key
, key
))
107 return event
->env_vars
[i
].value
;
114 * Appends a key-value pair described by the second argument to the
117 * @1 A hotplug event structure
118 * @1 An item in format "key=value" to be appended
120 * Returns: 0 if success, -1 if the string is malformed
122 int add_hotplug2_event_env(struct hotplug2_event_t
*event
, char *item
) {
125 ptr
= strchr(item
, '=');
132 event
->env_vars
= xrealloc(event
->env_vars
, sizeof(struct env_var_t
) * event
->env_vars_c
);
133 event
->env_vars
[event
->env_vars_c
- 1].key
= strdup(item
);
134 event
->env_vars
[event
->env_vars_c
- 1].value
= strdup(ptr
+ 1);
137 * Variables not generated by kernel but demanded nonetheless...
139 * TODO: Split this to a different function
141 if (!strcmp(item
, "DEVPATH")) {
143 event
->env_vars
= xrealloc(event
->env_vars
, sizeof(struct env_var_t
) * event
->env_vars_c
);
144 event
->env_vars
[event
->env_vars_c
- 1].key
= strdup("DEVICENAME");
145 tmp
= strdup(ptr
+ 1);
146 event
->env_vars
[event
->env_vars_c
- 1].value
= strdup(basename(tmp
));
156 * Duplicates all allocated memory of a source hotplug event
157 * and returns a new hotplug event, an identical copy of the
160 * @1 Source hotplug event structure
162 * Returns: A copy of the source event structure
164 inline struct hotplug2_event_t
*dup_hotplug2_event(struct hotplug2_event_t
*src
) {
165 struct hotplug2_event_t
*dest
;
168 dest
= xmalloc(sizeof(struct hotplug2_event_t
));
169 dest
->action
= src
->action
;
170 dest
->env_vars_c
= src
->env_vars_c
;
171 dest
->env_vars
= xmalloc(sizeof(struct env_var_t
) * dest
->env_vars_c
);
172 dest
->plain_s
= src
->plain_s
;
173 dest
->plain
= xmalloc(dest
->plain_s
);
174 memcpy(dest
->plain
, src
->plain
, dest
->plain_s
);
176 for (i
= 0; i
< src
->env_vars_c
; i
++) {
177 dest
->env_vars
[i
].key
= strdup(src
->env_vars
[i
].key
);
178 dest
->env_vars
[i
].value
= strdup(src
->env_vars
[i
].value
);
185 * Parses a string into a hotplug event structurs.
187 * @1 The event string (not null terminated)
188 * @2 The size of the event string
190 * Returns: A new event structure
192 inline struct hotplug2_event_t
*get_hotplug2_event(char *event_str
, int size
) {
194 struct hotplug2_event_t
*event
;
197 ptr
= strchr(event_str
, '@');
203 event
= xmalloc(sizeof(struct hotplug2_event_t
));
204 event
->action
= get_hotplug2_event_action(event_str
);
205 event
->env_vars_c
= 0;
206 event
->env_vars
= NULL
;
207 event
->plain_s
= size
;
208 event
->plain
= xmalloc(size
);
209 memcpy(event
->plain
, event_str
, size
);
211 skip
= ++ptr
- event_str
;
215 add_hotplug2_event_env(event
, ptr
);
225 * Evaluates an argument into a true/false value.
229 * @3 pointer to output value
231 * Returns: 0 if success, -1 otherwise
233 int get_bool_opt(char *argv
, char *name
, int *value
) {
236 if (!strncmp(argv
, "--no-", 5)) {
241 if (!strncmp(argv
, "--", 2)) {
249 if (!strcmp(argv
, name
)) {
258 * Performs a cleanup; closes uevent socket, resets signal
259 * handlers, waits for all the children.
266 close(netlink_socket
);
268 signal(SIGUSR1
, SIG_DFL
);
269 signal(SIGINT
, SIG_DFL
);
270 signal(SIGCHLD
, SIG_DFL
);
272 INFO("cleanup", "Waiting for children.");
273 /* Wait for our possible children... */
274 while ((p
= wait(NULL
)) != -1)
275 DBG("cleanup", "pid: %d.", p
);
276 INFO("cleanup", "All children terminated.");
280 * Handles all signals.
282 * @1 Signal identifier
286 void sighandler(int sig
) {
291 * SIGINT simply tells that yes, we caught the signal, and
295 INFO("sighandler", "Obtained SIGINT, quitting.");
301 * SIGUSR1 is handled so that if we have turned off persistency
302 * and have processed all events, we quit.
305 persistent
= !persistent
;
306 INFO("sighandler", "Changed persistency to: %s", persistent
? "yes" : "no");
308 INFO("sighandler", "No more events to be processed, quitting.");
315 * SIGCHLD helps us to figure out when a child died and
316 * what kind of child it was. It may also invoke termination.
320 p
= waitpid (WAIT_ANY
, NULL
, WNOHANG
);
324 DBG("sighandler", "caught pid: %d.", p
);
325 if (p
== coldplug_p
) {
326 DBG("sighandler", "coldplug_p: %d.", coldplug_p
);
327 coldplug_p
= FORK_FINISHED
;
329 child
= remove_child_by_pid(child
, p
, NULL
, &child_c
);
332 DBG("sighandler", "child_c: %d, child: %p, highest_seqnum: %lld, cur_seqnum: %lld, coldplug_p: %d.\n", child_c
, child
, highest_seqnum
, get_kernel_seqnum(), coldplug_p
);
336 INFO("sighandler", "No more events to be processed, quitting.");
346 * Execute all rules for this particular event.
348 * @1 Hotplug event structure
349 * @2 Rules structure, containing array of rules
353 void perform_action(struct hotplug2_event_t
*event
, struct rules_t
*rules
) {
356 for (i
= 0; i
< rules
->rules_c
; i
++) {
357 rv
= rule_execute(event
, &rules
->rules
[i
]);
362 free_hotplug2_event(event
);
366 * Iterates through all rules, and performs an AND between all flags that
367 * would apply during execution (ie. all rules that have conditions matching
368 * the hotplug event).
370 * @1 Hotplug event structure
371 * @2 Rules structure, containing array of rules
373 * Returns: Flags that apply to all matching rules
375 int flags_eval(struct hotplug2_event_t
*event
, struct rules_t
*rules
) {
376 int flags
= FLAG_ALL
;
380 for (i
= 0; i
< rules
->rules_c
; i
++) {
383 for (j
= 0; j
< rules
->rules
[i
].conditions_c
; j
++) {
384 if (rule_condition_eval(event
, &rules
->rules
[i
].conditions
[j
]) != EVAL_MATCH
) {
391 * Logical AND between flags we've got already and
392 * those we're adding.
395 rule_flags(&rules
->rules
[i
]);
396 flags
&= rules
->rules
[i
].flags
;
401 * A little trick; if no rule matched, we return FLAG_ALL
402 * and have it skipped completely.
408 #define perform_action(event, rules)
412 * Blindly modprobe the modalias, nothing more.
414 * @1 Hotplug event structure
415 * @2 Modalias to be loaded
419 void perform_dumb_action(struct hotplug2_event_t
*event
, char *modalias
) {
420 free_hotplug2_event(event
);
421 execl(modprobe_command
, modprobe_command
, "-q", modalias
, NULL
);
425 * Attempt to figure out whether our modprobe command can handle modalias.
426 * If not, use our own wrapper.
428 * Returns: 0 if success, -1 otherwise
430 int get_modprobe_command() {
442 ERROR("modprobe_command","Unable to fork.");
451 execlp("/sbin/modprobe", "/sbin/modprobe", "--version", NULL
);
457 fp
= fdopen(fds
[0], "r");
458 fread(buf
, 1, 17, fp
);
462 * module-init-tools can handle aliases.
463 * If we do not have a match, we use hotplug2-depwrap,
464 * even though our modprobe can do fnmatch aliases,
465 * which is the case of eg. busybox.
467 if (!strcmp(buf
, "module-init-tools")) {
468 modprobe_command
= "/sbin/modprobe";
470 modprobe_command
= "/sbin/hotplug2-depwrap";
479 int main(int argc
, char *argv
[]) {
483 static char buffer
[UEVENT_BUFFER_SIZE
+512];
484 struct hotplug2_event_t
*tmpevent
;
485 char *modalias
, *seqnum
;
486 event_seqnum_t cur_seqnum
;
493 char *coldplug_command
= NULL
;
494 char *rules_file
= HOTPLUG2_RULE_PATH
;
496 struct pollfd msg_poll
;
498 struct hotplug2_event_t
*backlog
= NULL
;
499 struct hotplug2_event_t
*backlog_tail
= NULL
;
502 struct rules_t
*rules
= NULL
;
503 struct filemap_t filemap
;
505 struct options_t bool_options
[] = {
506 {"persistent", &persistent
},
507 {"coldplug", &coldplug
},
508 {"udevtrigger", &coldplug
}, /* compatibility */
509 {"override", &override
},
517 * We parse all the options...
519 for (argc
--; argc
> 0; argc
--) {
524 for (i
= 0; bool_options
[i
].name
!= NULL
; i
++) {
525 if (!get_bool_opt(*argv
, bool_options
[i
].name
, bool_options
[i
].value
)) {
527 * Bool options are --option or --no-options. If we handled
528 * it, quit iterating.
532 if (!strcmp(*argv
, "--max-children")) {
538 max_child_c
= strtol(*argv
, NULL
, 0);
539 } else if (!strcmp(*argv
, "--set-coldplug-cmd")) {
545 coldplug_command
= *argv
;
546 } else if (!strcmp(*argv
, "--set-modprobe-cmd")) {
552 modprobe_command
= *argv
;
553 } else if (!strcmp(*argv
, "--set-rules-file")) {
567 * We don't use rules, so we use dumb mode only.
572 * We're not in dumb mode, parse the rules. If we fail,
573 * faillback to dumb mode.
576 if (map_file(rules_file
, &filemap
)) {
577 ERROR("rules parse","Unable to open/mmap rules file.");
582 rules
= rules_from_config((char*)(filemap
.map
), NULL
);
584 ERROR("rules parse","Unable to parse rules file.");
588 unmap_file(&filemap
);
592 ERROR("rules parse","Parsing rules failed, switching to dumb mode.");
596 * No modprobe command specified, let's autodetect it.
598 if (!modprobe_command
)
600 if (get_modprobe_command()) {
601 ERROR("modprobe_command","Unable to autodetect modprobe command.");
604 DBG("modprobe_command", "Using modprobe: `%s'.", modprobe_command
);
608 * Open netlink socket to read the uevents
610 netlink_socket
= init_netlink_socket(NETLINK_BIND
);
611 msg_poll
.fd
= netlink_socket
;
612 msg_poll
.events
= POLLIN
;
614 if (netlink_socket
== -1) {
615 ERROR("netlink init","Unable to open netlink socket.");
622 signal(SIGUSR1
, sighandler
);
623 signal(SIGINT
, sighandler
);
624 signal(SIGCHLD
, sighandler
);
627 * If we desire coldplugging, we initiate it right now.
630 if (coldplug_command
== NULL
)
631 coldplug_command
= UDEVTRIGGER_COMMAND
;
633 switch (coldplug_p
) {
635 ERROR("coldplug","Coldplug fork failed: %s.", strerror(errno
));
636 perror("coldplug fork failed");
640 execlp(coldplug_command
, coldplug_command
, NULL
);
641 ERROR("coldplug","Coldplug exec ('%s') failed: %s.", coldplug_command
, strerror(errno
));
646 coldplug_p
= FORK_FINISHED
;
650 * Main loop reading uevents
653 if ((n_backlog
> 0) && (child_c
< max_child_c
)) {
654 /* dequeue backlog message */
656 backlog
= backlog
->next
;
658 if (backlog_tail
== tmpevent
)
662 * Read the uevent packet
664 if (n_backlog
>= HOTPLUG2_MSG_BACKLOG
) {
665 usleep(HOTPLUG2_THROTTLE_INTERVAL
* 1000);
669 if ((n_backlog
> 0) && (child_c
>= max_child_c
)) {
671 msg_poll
.revents
= 0;
672 fds
= poll(&msg_poll
, 1, HOTPLUG2_THROTTLE_INTERVAL
);
679 size
= recv(netlink_socket
, &buffer
, sizeof(buffer
), 0);
685 * Parse the event into an event structure
687 tmpevent
= get_hotplug2_event(buffer
, size
);
689 if (tmpevent
== NULL
) {
690 ERROR("reading events", "Malformed event read (missing action prefix).");
696 * Look up two important items of the event
698 modalias
= get_hotplug2_value_by_key(tmpevent
, "MODALIAS");
699 seqnum
= get_hotplug2_value_by_key(tmpevent
, "SEQNUM");
702 * Seqnum is necessary not to end up in a race with the kernel.
704 if (seqnum
== NULL
) {
705 free_hotplug2_event(tmpevent
);
706 ERROR("reading events", "Malformed event read (missing SEQNUM).");
711 * Maintain seqnum continuity
713 cur_seqnum
= strtoull(seqnum
, NULL
, 0);
714 if (cur_seqnum
> highest_seqnum
)
715 highest_seqnum
= cur_seqnum
;
718 * If we are in smart mode, we'll always pass. If we're in dumb mode,
719 * we only pass events that have 'add' action and have modalias set.
721 if ((dumb
&& tmpevent
->action
== ACTION_ADD
&& modalias
!= NULL
) || (!dumb
)) {
723 * Pre-evaluation of the flags
725 if (!dumb
&& override
) {
726 flags
= flags_eval(tmpevent
, rules
);
728 DBG("flags", "flag returned: %8x", flags
);
730 if (flags
== FLAG_ALL
)
737 * We have more children than we want. Wait until SIGCHLD handler reduces
740 * Unless, of course, we've specified otherwise and no rules that match
743 if (!(flags
& FLAG_NOTHROTTLE
) && (child_c
>= max_child_c
)) {
744 /* log the packet and process it later */
746 backlog_tail
->next
= tmpevent
;
749 tmpevent
->next
= NULL
;
750 backlog_tail
= tmpevent
;
755 sigemptyset(&block_mask
);
756 sigaddset(&block_mask
, SIGCHLD
);
757 sigprocmask(SIG_BLOCK
, &block_mask
, 0);
761 ERROR("event", "fork failed: %s.", strerror(errno
));
765 * TODO: We do not have to dup here, or do we?
767 sigprocmask(SIG_UNBLOCK
, &block_mask
, 0);
768 signal(SIGCHLD
, SIG_DFL
);
769 signal(SIGUSR1
, SIG_DFL
);
771 perform_action(dup_hotplug2_event(tmpevent
), rules
);
773 perform_dumb_action(dup_hotplug2_event(tmpevent
), modalias
);
777 DBG("spawn", "spawning: %d.", p
);
778 child
= add_child(child
, p
, cur_seqnum
);
782 sigprocmask(SIG_UNBLOCK
, &block_mask
, 0);
785 free_hotplug2_event(tmpevent
);
789 signal(SIGUSR1
, SIG_DFL
);
790 signal(SIGINT
, SIG_DFL
);
791 signal(SIGCHLD
, SIG_DFL
);