使用netlink与内核通信获取U盘插拔信息
Hotplug uevent
uevent is just string of some special format that is sent via netlink socket. Example:
add@/class/input/input9/mouse2\0 // message
ACTION=add\0 // action type
DEVPATH=/class/input/input9/mouse2\0 // path in /sys
SUBSYSTEM=input\0 // subsystem (class)
SEQNUM=1064\0 // sequence number
PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.1/usb2/22/22:1.0\0 // device path in /sys
PHYSDEVBUS=usb\0 // bus
PHYSDEVDRIVER=usbhid\0 // driver
MAJOR=13\0 // major number
MINOR=34\0", // minor number
mdev
, the udev
for embedded systems
Example 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>
#include <sys/poll.h>
static int init_hotplug_sock(void)
{
struct sockaddr_nl snl;
const int buffersize = 16 * 1024 * 1024;
int retval;
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = -1;
int hotplug_sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (hotplug_sock == -1) {
printf("error getting socket: %s", strerror(errno));
return -1;
}
setsockopt(hotplug_sock, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
retval = bind(hotplug_sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
if (retval < 0) {
printf("bind failed: %s", strerror(errno));
close(hotplug_sock);
hotplug_sock = -1;
return -1;
}
return hotplug_sock;
}
main(void)
{
init_hotplug_sock();
while(1){
char buf[UEVENT_BUFFER_SIZE*2] = {0};
recv(hotplug_sock, &buf, sizeof(buf), 0);
printf("\033[31m%s\n\033[0m", buf);
printf("==============================\n");
}
}
这种方式只可以输出uevent
的第一行内容,是由于recv
方式导致,完善如下
Example 2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>
#include <sys/poll.h>
static int init_hotplug_sock(void)
{
struct sockaddr_nl snl;
const int buffersize = 16 * 1024 * 1024;
int retval;
struct pollfd pfd;
char buf[512];
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
snl.nl_family = AF_NETLINK;
snl.nl_pid = getpid();
snl.nl_groups = -1;
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (pfd.fd == -1) {
printf("error getting socket: %s", strerror(errno));
return -1;
}
retval = bind(pfd.fd, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl));
while (-1!=poll(&pfd, 1, -1)) {
int i, len = recv(pfd.fd, buf, sizeof(buf), 0);
if (len == -1) die("recv\n");
// Print the data to stdout.
printf("@@@@@@@@@@@@@@@@@\n");
i = 0;
while (i<len) {
if(strstr(buf+i, "add@") || strstr(buf+i, "remove@")) {
printf("\033[31m%s\n\033[0m", buf+i);
}
else if(strstr(buf+i, "ACTION=")) {
}
else if(strstr(buf+i, "SUBSYSTEM=")) {
if(!strstr(buf+i, "usb")) {
len = 0;
break;
}
}
else if(strstr(buf+i, "DEVTYPE=")) {
if(!strstr(buf+i, "usb_device")) {
len = 0;
break;
}
}
else if(strstr(buf+i, "PRODUCT=")) {
printf("\033[31m%s\n\033[0m", buf+i);
close(pfd.fd);
return 0;
}
i += strlen(buf+i)+1;
}
}
return pfd.fd;
}
Example 3
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <errno.h>
#include <sys/poll.h>
void die(char *s)
{
write(2,s,strlen(s));
exit(1);
}
int netlink_test(void)
{
struct sockaddr_nl nls;
struct pollfd pfd;
char buf[512];
// Open hotplug event netlink socket
memset(&nls,0,sizeof(struct sockaddr_nl));
nls.nl_family = AF_NETLINK;
nls.nl_pid = getpid();
nls.nl_groups = -1; //<--add this so can receive from kernel broadcast
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (pfd.fd==-1)
die("Not root\n");
// Listen to netlink socket
if (bind(pfd.fd, (void *)&nls, sizeof(struct sockaddr_nl)))
die("Bind failed\n");
while (-1!=poll(&pfd, 1, -1)) {
int i, len = recv(pfd.fd, buf, sizeof(buf), 0);
if (len == -1) die("recv\n");
// Print the data to stdout.
i = 0;
while (i<len) {
printf("\033[33m%s\n\033[0m", buf+i);
i += strlen(buf+i)+1;
}
}
die("poll\n");
// Dear gcc: shut up.
return 0;
}