您的位置:首页 > 运维架构 > Linux

Linux Uevent和Netlink socket

2016-07-12 10:26 441 查看
Uevent是一种在内核空间和用户空间之间通信的机制,主要用于热插拔事件(hotplug)。

编辑获取热插拔事件的源文件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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: