//从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); }