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>
25 #include "mem_utils.h"
28 #include "childlist.h"
30 #define TERMCONDITION (persistent == 0 && \
31 coldplug_p == FORK_FINISHED && \
33 highest_seqnum == get_kernel_seqnum())
35 event_seqnum_t highest_seqnum
= 0;
43 struct hotplug2_child_t
*child
;
46 char *modprobe_command
= NULL
;
48 inline void free_hotplug2_event(struct hotplug2_event_t
*event
) {
51 for (i
= 0; i
< event
->env_vars_c
; i
++) {
52 free(event
->env_vars
[i
].key
);
53 free(event
->env_vars
[i
].value
);
55 free(event
->env_vars
);
60 inline int get_hotplug2_event_action(char *action
) {
61 if (!strcmp(action
, "add"))
64 if (!strcmp(action
, "remove"))
67 return ACTION_UNKNOWN
;
70 char *get_hotplug2_value_by_key(struct hotplug2_event_t
*event
, char *key
) {
73 for (i
= 0; i
< event
->env_vars_c
; i
++) {
74 if (!strcmp(event
->env_vars
[i
].key
, key
))
75 return event
->env_vars
[i
].value
;
81 inline int add_hotplug2_event_env(struct hotplug2_event_t
*event
, char *item
) {
84 ptr
= strchr(item
, '=');
91 event
->env_vars
= xrealloc(event
->env_vars
, sizeof(struct env_var_t
) * event
->env_vars_c
);
92 event
->env_vars
[event
->env_vars_c
- 1].key
= strdup(item
);
93 event
->env_vars
[event
->env_vars_c
- 1].value
= strdup(ptr
+ 1);
96 * Variables not generated by kernel but demanded nonetheless...
98 if (!strcmp(item
, "DEVPATH")) {
100 event
->env_vars
= xrealloc(event
->env_vars
, sizeof(struct env_var_t
) * event
->env_vars_c
);
101 event
->env_vars
[event
->env_vars_c
- 1].key
= strdup("DEVICENAME");
102 tmp
= strdup(ptr
+ 1);
103 event
->env_vars
[event
->env_vars_c
- 1].value
= strdup(basename(tmp
));
112 inline struct hotplug2_event_t
*dup_hotplug2_event(struct hotplug2_event_t
*src
) {
113 struct hotplug2_event_t
*dest
;
116 dest
= xmalloc(sizeof(struct hotplug2_event_t
));
117 dest
->action
= src
->action
;
118 dest
->env_vars_c
= src
->env_vars_c
;
119 dest
->env_vars
= xmalloc(sizeof(struct env_var_t
) * dest
->env_vars_c
);
120 dest
->plain_s
= src
->plain_s
;
121 dest
->plain
= xmalloc(dest
->plain_s
);
122 memcpy(dest
->plain
, src
->plain
, dest
->plain_s
);
124 for (i
= 0; i
< src
->env_vars_c
; i
++) {
125 dest
->env_vars
[i
].key
= strdup(src
->env_vars
[i
].key
);
126 dest
->env_vars
[i
].value
= strdup(src
->env_vars
[i
].value
);
132 inline struct hotplug2_event_t
*get_hotplug2_event(char *event_str
, int size
) {
134 struct hotplug2_event_t
*event
;
137 ptr
= strchr(event_str
, '@');
143 event
= xmalloc(sizeof(struct hotplug2_event_t
));
144 event
->action
= get_hotplug2_event_action(event_str
);
145 event
->env_vars_c
= 0;
146 event
->env_vars
= NULL
;
147 event
->plain_s
= size
;
148 event
->plain
= xmalloc(size
);
149 memcpy(event
->plain
, event_str
, size
);
151 skip
= ++ptr
- event_str
;
155 add_hotplug2_event_env(event
, ptr
);
164 inline event_seqnum_t
get_kernel_seqnum() {
170 strcpy(filename
, sysfs_seqnum_path
);
172 fp
= fopen(filename
, "r");
176 fread(seqnum
, 1, 64, fp
);
179 return strtoull(seqnum
, NULL
, 0);
182 inline int init_netlink_socket() {
184 struct sockaddr_nl snl
;
185 int buffersize
= 16 * 1024 * 1024;
187 memset(&snl
, 0x00, sizeof(struct sockaddr_nl
));
188 snl
.nl_family
= AF_NETLINK
;
189 snl
.nl_pid
= getpid();
191 netlink_socket
= socket(PF_NETLINK
, SOCK_DGRAM
, NETLINK_KOBJECT_UEVENT
);
192 if (netlink_socket
== -1) {
193 ERROR("opening netlink","Failed socket: %s.", strerror(errno
));
197 if (setsockopt(netlink_socket
, SOL_SOCKET
, SO_RCVBUFFORCE
, &buffersize
, sizeof(buffersize
))) {
198 ERROR("opening netlink","Failed setsockopt: %s. (non-critical)", strerror(errno
));
200 /* Somewhat safe default. */
203 if (setsockopt(netlink_socket
, SOL_SOCKET
, SO_RCVBUF
, &buffersize
, sizeof(buffersize
))) {
204 ERROR("opening netlink","Failed setsockopt: %s. (critical)", strerror(errno
));
208 if (bind(netlink_socket
, (struct sockaddr
*) &snl
, sizeof(struct sockaddr_nl
))) {
209 ERROR("opening netlink","Failed bind: %s.", strerror(errno
));
210 close(netlink_socket
);
214 return netlink_socket
;
217 int get_bool_opt(char *argv
, char *name
, int *value
) {
220 if (!strncmp(argv
, "--no-", 5)) {
225 if (!strncmp(argv
, "--", 2)) {
233 if (!strcmp(argv
, name
)) {
244 close(netlink_socket
);
246 signal(SIGUSR1
, SIG_DFL
);
247 signal(SIGINT
, SIG_DFL
);
248 signal(SIGCHLD
, SIG_DFL
);
250 INFO("cleanup", "Waiting for children.");
251 /* Wait for our possible children... */
252 while ((p
= wait(NULL
)) != -1)
253 DBG("cleanup", "pid: %d.", p
);
254 INFO("cleanup", "All children terminated.");
257 void sighandler(int sig
) {
262 * SIGINT simply tells that yes, we caught the signal, and
266 INFO("sighandler", "Obtained SIGINT, quitting.");
272 * SIGUSR1 is handled so that if we have turned off persistency
273 * and have processed all events, we quit.
276 persistent
= !persistent
;
277 INFO("sighandler", "Changed persistency to: %s", persistent
? "yes" : "no");
279 INFO("sighandler", "No more events to be processed, quitting.");
286 * SIGCHLD helps us to figure out when a child died and
287 * what kind of child it was. It may also invoke termination.
291 p
= waitpid (WAIT_ANY
, NULL
, WNOHANG
);
295 DBG("sighandler", "caught pid: %d.", p
);
296 if (p
== coldplug_p
) {
297 DBG("sighandler", "coldplug_p: %d.", coldplug_p
);
298 coldplug_p
= FORK_FINISHED
;
300 child
= remove_child_by_pid(child
, p
, NULL
, &child_c
);
303 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
);
307 INFO("sighandler", "No more events to be processed, quitting.");
316 void perform_action(struct hotplug2_event_t
*event
, struct rules_t
*rules
) {
319 for (i
= 0; i
< rules
->rules_c
; i
++) {
320 rv
= rule_execute(event
, &rules
->rules
[i
]);
325 free_hotplug2_event(event
);
329 void perform_dumb_action(struct hotplug2_event_t
*event
, char *modalias
) {
330 free_hotplug2_event(event
);
331 execl(modprobe_command
, modprobe_command
, "-q", modalias
, NULL
);
334 int get_modprobe_command() {
346 ERROR("modprobe_command","Unable to fork.");
355 execlp("/sbin/modprobe", "/sbin/modprobe", "--version", NULL
);
361 fp
= fdopen(fds
[0], "r");
362 fread(buf
, 1, 17, fp
);
366 * module-init-tools can handle aliases.
367 * If we do not have a match, we use hotplug2-depwrap,
368 * even though our modprobe can do fnmatch aliases,
369 * which is the case of eg. busybox.
371 if (!strcmp(buf
, "module-init-tools")) {
372 modprobe_command
= "/sbin/modprobe";
374 modprobe_command
= "/sbin/hotplug2-depwrap";
383 int main(int argc
, char *argv
[]) {
384 static char buffer
[UEVENT_BUFFER_SIZE
+512];
385 struct hotplug2_event_t
*tmpevent
;
386 char *modalias
, *seqnum
;
387 event_seqnum_t cur_seqnum
;
393 char *coldplug_command
= NULL
;
396 struct rules_t
*rules
= NULL
;
401 struct options_t bool_options
[] = {
402 {"persistent", &persistent
},
403 {"coldplug", &coldplug
},
404 {"udevtrigger", &coldplug
}, /* compatibility */
411 for (argc
--; argc
> 0; argc
--) {
413 for (i
= 0; bool_options
[i
].name
!= NULL
; i
++) {
414 if (!get_bool_opt(*argv
, bool_options
[i
].name
, bool_options
[i
].value
)) {
417 if (!strcmp(*argv
, "--max-children")) {
423 max_child_c
= strtol(*argv
, NULL
, 0);
424 } else if (!strcmp(*argv
, "--set-coldplug-cmd")) {
430 coldplug_command
= *argv
;
431 } else if (!strcmp(*argv
, "--set-modprobe-cmd")) {
437 modprobe_command
= *argv
;
445 filemap
= MAP_FAILED
;
446 rule_fd
= open(HOTPLUG2_RULE_PATH
, O_RDONLY
| O_NOATIME
);
449 ERROR("rules parse","Unable to open rules file: %s.", strerror(errno
));
453 if (fstat(rule_fd
, &statbuf
)) {
455 ERROR("rules parse","Unable to stat rules file: %s.", strerror(errno
));
459 filemap
= mmap(0, statbuf
.st_size
, PROT_READ
, MAP_SHARED
, rule_fd
, 0);
460 if (filemap
== MAP_FAILED
) {
462 ERROR("rules parse","Unable to mmap rules file: %s.", strerror(errno
));
466 rules
= rules_from_config((char*)filemap
);
468 ERROR("rules parse","Unable to parse rules file.");
473 if (filemap
!= MAP_FAILED
)
474 munmap(filemap
, statbuf
.st_size
);
479 ERROR("rules parse","Parsing rules failed, switching to dumb mode.");
480 } else if (!modprobe_command
)
482 if (dumb
&& !modprobe_command
)
485 if (get_modprobe_command()) {
486 ERROR("modprobe_command","Unable to autodetect modprobe command.");
489 DBG("modprobe_command", "Using modprobe: `%s'.", modprobe_command
);
492 netlink_socket
= init_netlink_socket();
494 if (netlink_socket
== -1) {
495 ERROR("netlink init","Unable to open netlink socket.");
502 signal(SIGUSR1
, sighandler
);
503 signal(SIGINT
, sighandler
);
504 signal(SIGCHLD
, sighandler
);
507 if (coldplug_command
== NULL
)
508 coldplug_command
= UDEVTRIGGER_COMMAND
;
510 switch (coldplug_p
) {
512 ERROR("coldplug","Coldplug fork failed: %s.", strerror(errno
));
513 perror("coldplug fork failed");
517 execlp(coldplug_command
, coldplug_command
, NULL
);
518 ERROR("coldplug","Coldplug exec ('%s') failed: %s.", coldplug_command
, strerror(errno
));
523 coldplug_p
= FORK_FINISHED
;
527 size
= recv(netlink_socket
, &buffer
, sizeof(buffer
), 0);
532 tmpevent
= get_hotplug2_event(buffer
, size
);
534 if (tmpevent
== NULL
) {
535 ERROR("reading events", "Malformed event read (missing action prefix).");
539 modalias
= get_hotplug2_value_by_key(tmpevent
, "MODALIAS");
540 seqnum
= get_hotplug2_value_by_key(tmpevent
, "SEQNUM");
542 if (seqnum
== NULL
) {
543 free_hotplug2_event(tmpevent
);
544 ERROR("reading events", "Malformed event read (missing SEQNUM).");
548 cur_seqnum
= strtoull(seqnum
, NULL
, 0);
549 if (cur_seqnum
> highest_seqnum
)
550 highest_seqnum
= cur_seqnum
;
552 if (tmpevent
->action
== ACTION_REMOVE
|| (!dumb
|| modalias
!= NULL
)) {
554 * We have more children than we want. Wait until SIGCHLD handler reduces
557 while (child_c
>= max_child_c
) {
558 usleep(HOTPLUG2_THROTTLE_INTERVAL
);
561 sigemptyset(&block_mask
);
562 sigaddset(&block_mask
, SIGCHLD
);
563 sigprocmask(SIG_BLOCK
, &block_mask
, 0);
567 ERROR("event","fork failed: %s.", strerror(errno
));
570 sigprocmask(SIG_UNBLOCK
, &block_mask
, 0);
571 signal(SIGCHLD
, SIG_DFL
);
572 signal(SIGUSR1
, SIG_DFL
);
575 perform_action(dup_hotplug2_event(tmpevent
), rules
);
576 else if (tmpevent
->action
== ACTION_ADD
)
578 perform_dumb_action(dup_hotplug2_event(tmpevent
), modalias
);
582 DBG("spawn", "spawning: %d.", p
);
583 child
= add_child(child
, p
, cur_seqnum
);
587 sigprocmask(SIG_UNBLOCK
, &block_mask
, 0);
590 free_hotplug2_event(tmpevent
);
594 signal(SIGUSR1
, SIG_DFL
);
595 signal(SIGINT
, SIG_DFL
);
596 signal(SIGCHLD
, SIG_DFL
);