Linux Uevent和Netlink socket
2016-07-12 10:26
441 查看
Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug)。
编辑获取热插拔事件的源文件get_uevent.c
以插拔优盘为例从内核中获取具体的事件。
编译运行
拔出优盘时获取的信息:
编辑获取热插拔事件的源文件get_uevent.c
#define _GNU_SOURCE #include <unistd.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #include <stddef.h> #include <string.h> #include <fcntl.h> #include <time.h> #include <sys/socket.h> #include <sys/user.h> #include <sys/un.h> #include <linux/types.h> #include <linux/netlink.h> #define HOTPLUG_BUFFER_SIZE 1024 #define HOTPLUG_NUM_ENVP 32 #define OBJECT_SIZE 512 struct uevent { void *next; char buffer[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; char *devpath; char *action; char *envp[HOTPLUG_NUM_ENVP]; }; static struct uevent * alloc_uevent (void) { return (struct uevent *)malloc(sizeof(struct uevent)); } int main(int argc, char *argv[]) { int sock; struct sockaddr_nl snl; struct sockaddr_un sun; socklen_t addrlen; int retval; int rcvbufsz = 128*1024; int rcvsz = 0; int rcvszsz = sizeof(rcvsz); unsigned int *prcvszsz = (unsigned int *)&rcvszsz; pthread_attr_t attr; const int feature_on = 1; memset(&snl, 0x00, sizeof(struct sockaddr_nl)); snl.nl_family = AF_NETLINK; snl.nl_pid = getpid(); snl.nl_groups = 0x01; sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (sock == -1) { printf("error getting socket, exit\n"); return 1; } printf("reading events from kernel.\n"); retval = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbufsz, sizeof(rcvbufsz)); if (retval < 0) { printf("error setting receive buffer size for socket, exit\n"); exit(1); } retval = getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvsz, prcvszsz); if (retval < 0) { printf("error setting receive buffer size for socket, exit\n"); exit(1); } printf("receive buffer size for socket is %u.\n", rcvsz); /* enable receiving of the sender credentials */ setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &feature_on, sizeof(feature_on)); retval = bind(sock, (struct sockaddr *) &snl, sizeof(struct sockaddr_nl)); if (retval < 0) { printf("bind failed, exit\n"); goto exit; } while(1) { int i; char *pos; size_t bufpos; ssize_t buflen; struct uevent *uev; char *buffer; struct msghdr smsg; struct iovec iov; struct cmsghdr *cmsg; struct ucred *cred; char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; static char buf[HOTPLUG_BUFFER_SIZE + OBJECT_SIZE]; memset(buf, 0x00, sizeof(buf)); iov.iov_base = &buf; iov.iov_len = sizeof(buf); memset (&smsg, 0x00, sizeof(struct msghdr)); smsg.msg_iov = &iov; smsg.msg_iovlen = 1; smsg.msg_control = cred_msg; smsg.msg_controllen = sizeof(cred_msg); buflen = recvmsg(sock, &smsg, 0); if (buflen < 0) { if (errno != EINTR) printf("error receiving message.\n"); continue; } cmsg = CMSG_FIRSTHDR(&smsg); if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { printf("no sender credentials received, message ignored\n"); continue; } cred = (struct ucred *)CMSG_DATA(cmsg); if (cred->uid != 0) { printf("sender uid=%d, message ignored\n", cred->uid); continue; } /* skip header */ bufpos = strlen(buf) + 1; if (bufpos < sizeof("a@/d") || bufpos >= sizeof(buf)) { printf("invalid message length\n"); continue; } /* check message header */ if (strstr(buf, "@/") == NULL) { printf("unrecognized message header"); continue; } uev = alloc_uevent(); if (!uev) { printf("lost uevent, oom"); continue; } if ((size_t)buflen > sizeof(buf)-1) buflen = sizeof(buf)-1; /* * Copy the shared receive buffer contents to buffer private * to this uevent so we can immediately reuse the shared buffer. */ memcpy(uev->buffer, buf, HOTPLUG_BUFFER_SIZE + OBJECT_SIZE); buffer = uev->buffer; buffer[buflen] = '\0'; /* save start of payload */ bufpos = strlen(buffer) + 1; /* action string */ uev->action = buffer; pos = strchr(buffer, '@'); if (!pos) { printf("bad action string '%s'", buffer); continue; } pos[0] = '\0'; /* sysfs path */ uev->devpath = &pos[1]; /* hotplug events have the environment attached - reconstruct envp[] */ for (i = 0; (bufpos < (size_t)buflen) && (i < HOTPLUG_NUM_ENVP-1); i++) { int keylen; char *key; key = &buffer[bufpos]; keylen = strlen(key); uev->envp[i] = key; bufpos += keylen + 1; } uev->envp[i] = NULL; printf("uevent '%s' from '%s'.\n", uev->action, uev->devpath); /* print payload environment */ for (i = 0; uev->envp[i] != NULL; i++) printf("%s\n", uev->envp[i]); } return 0; exit: close(sock); return 1; }
以插拔优盘为例从内核中获取具体的事件。
编译运行
./get_uevent,然后插入一个优盘:
reading events from kernel. receive buffer size for socket is 262142. uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5'. ACTION=add DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5 SUBSYSTEM=usb MAJOR=189 MINOR=387 DEVNAME=bus/usb/004/004 DEVTYPE=usb_device DEVICE=/proc/bus/usb/004/004 PRODUCT=781/5590/100 TYPE=0/0/0 BUSNUM=004 DEVNUM=004 SEQNUM=1322 uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0'. ACTION=add DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0 SUBSYSTEM=usb DEVTYPE=usb_interface DEVICE=/proc/bus/usb/004/004 PRODUCT=781/5590/100 TYPE=0/0/0 INTERFACE=8/6/80 MODALIAS=usb:v0781p5590d0100dc00dsc00dp00ic08isc06ip50 SEQNUM=1323 uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4'. ACTION=add DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4 SUBSYSTEM=scsi DEVTYPE=scsi_host SEQNUM=1324 ... uevent 'change' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0'. ACTION=change DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0 SUBSYSTEM=scsi SDEV_MEDIA_CHANGE=1 DEVTYPE=scsi_device DRIVER=sd MODALIAS=scsi:t-0x00 SEQNUM=1331 uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdb'. ACTION=add DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdb SUBSYSTEM=block MAJOR=8 MINOR=16 DEVNAME=sdb DEVTYPE=disk SEQNUM=1332 uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdb/sdb1'. ACTION=add DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdb/sdb1 SUBSYSTEM=block MAJOR=8 MINOR=17 DEVNAME=sdb1 DEVTYPE=partition SEQNUM=1333 uevent 'add' from '/devices/virtual/bdi/8:16'. ACTION=add DEVPATH=/devices/virtual/bdi/8:16 SUBSYSTEM=bdi SEQNUM=1334`
拔出优盘时获取的信息:
uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/bsg/4:0:0:0'. ACTION=remove DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/bsg/4:0:0:0 SUBSYSTEM=bsg MAJOR=253 MINOR=1 DEVNAME=bsg/4:0:0:0 SEQNUM=1335 uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/scsi_device/4:0:0:0'. ACTION=remove DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/scsi_device/4:0:0:0 SUBSYSTEM=scsi_device SEQNUM=1336 uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/scsi_disk/4:0:0:0'. ... uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0'. ACTION=remove DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0 SUBSYSTEM=usb DEVTYPE=usb_interface DEVICE=/proc/bus/usb/004/004 PRODUCT=781/5590/100 TYPE=0/0/0 INTERFACE=8/6/80 MODALIAS=usb:v0781p5590d0100dc00dsc00dp00ic08isc06ip50 SEQNUM=1344 uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5'. ACTION=remove DEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5 SUBSYSTEM=usb MAJOR=189 MINOR=387 DEVNAME=bus/usb/004/004 DEVTYPE=usb_device DEVICE=/proc/bus/usb/004/004 PRODUCT=781/5590/100 TYPE=0/0/0 BUSNUM=004 DEVNUM=004 SEQNUM=1345 uevent 'remove' from '/host4/target4:0:0'. ACTION=remove DEVPATH=/host4/target4:0:0 SUBSYSTEM=scsi DEVTYPE=scsi_target SEQNUM=1346
相关文章推荐
- Android启动(一):Linux启动流程
- centos 安装 svn-1.9.4
- 【命令】iwconfig/iwpriv
- 嵌入式 Linux进程间通信(十一)——多线程简介
- Linux free -m 详细说明
- Linux下安装numpy,pandas,matplotlib
- linux 的终端字体色和背景色的修改方法(三)
- linux 的终端字体色和背景色的修改方法(二)
- CentOS7安装Mysql
- linux 的终端字体色和背景色的修改方法(一)
- linux 下 vim 学习笔记
- linux系统的指令集基础
- Linux中线程与CPU核的绑定
- Linux——top
- Linux安装MySQL的两种方法
- Linux 命令零星记录
- linux下重命名文件或文件夹
- linux 查看系统信息命令(比较全)
- libtool should recreate aclocalm4
- 初识Linux(三)--文件系统基本结构