//从system/core/init/devices.c中抽取的
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <linux/netlink.h>
struct uevent {
const char *action;
const char *path;
const char *subsystem;
const char *firmware;
int major;
int minor;
};
static int open_uevent_socket(void)
{
struct sockaddr_nl addr;
int sz = 64*1024; // XXX larger? udev uses
int on = 1;
int s;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;
s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(s < 0)
return -1;
setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
setsockopt(s, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
close(s);
return -1;
}
return s;
}
static void parse_event(const char *msg, struct uevent *uevent)
{
#if 1
uevent->action = "";
uevent->path = "";
uevent->subsystem = "";
uevent->firmware = "";
uevent->major = -1;
uevent->minor = -1;
/* currently ignoring SEQNUM */
while(*msg) {
printf("%s\n", msg);
if(!strncmp(msg, "ACTION=", 7)) {
msg += 7;
uevent->action = msg;
} else if(!strncmp(msg, "DEVPATH=", 8)) {
msg += 8;
uevent->path = msg;
} else if(!strncmp(msg, "SUBSYSTEM=", 10)) {
msg += 10;
uevent->subsystem = msg;
} else if(!strncmp(msg, "FIRMWARE=", 9)) {
msg += 9;
uevent->firmware = msg;
} else if(!strncmp(msg, "MAJOR=", 6)) {
msg += 6;
uevent->major = atoi(msg);
} else if(!strncmp(msg, "MINOR=", 6)) {
msg += 6;
uevent->minor = atoi(msg);
}
/* advance to after the next \0 */
while(*msg++)
;
}
printf("event { '%s', '%s', '%s', '%s', %d, %d }\n",
uevent->action, uevent->path, uevent->subsystem,
uevent->firmware, uevent->major, uevent->minor);
#endif
}
#define UEVENT_MSG_LEN 1024
void handle_device_fd(int fd)
{
printf("enter %s\n", __func__);
for(;;) {
char msg[UEVENT_MSG_LEN+2];
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
struct iovec iov = {msg, sizeof(msg)};
struct sockaddr_nl snl;
struct msghdr hdr = {&snl, sizeof(snl), &iov, 1, cred_msg, sizeof(cred_msg), 0};
ssize_t n = recvmsg(fd, &hdr, 0);
if (n <= 0) {
break;
}
if ((snl.nl_groups != 1) || (snl.nl_pid != 0)) {
/* ignoring non-kernel netlink multicast message */
continue;
}
struct cmsghdr * cmsg = CMSG_FIRSTHDR(&hdr);
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
/* no sender credentials received, ignore message */
continue;
}
struct ucred * cred = (struct ucred *)CMSG_DATA(cmsg);
if (cred->uid != 0) {
/* message from non-root user, ignore */
continue;
}
if(n >= UEVENT_MSG_LEN) /* overflow -- discard */
continue;
msg[n] = '\0';
msg[n+1] = '\0';
struct uevent uevent;
parse_event(msg, &uevent);
}
}
int main(void)
{
int fd = 0;
fd = open_uevent_socket();
if (fd < 0) {
printf("error!\n");
return -1;
}
handle_device_fd(fd);
}