Linux Uevent和Netlink socket

来源:互联网 发布:centos 7 nginx 目录 编辑:程序博客网 时间:2024/06/04 00:58

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         512struct 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=addDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5SUBSYSTEM=usbMAJOR=189MINOR=387DEVNAME=bus/usb/004/004DEVTYPE=usb_deviceDEVICE=/proc/bus/usb/004/004PRODUCT=781/5590/100TYPE=0/0/0BUSNUM=004DEVNUM=004SEQNUM=1322uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0'.ACTION=addDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0SUBSYSTEM=usbDEVTYPE=usb_interfaceDEVICE=/proc/bus/usb/004/004PRODUCT=781/5590/100TYPE=0/0/0INTERFACE=8/6/80MODALIAS=usb:v0781p5590d0100dc00dsc00dp00ic08isc06ip50SEQNUM=1323uevent 'add' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4'.ACTION=addDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4SUBSYSTEM=scsiDEVTYPE=scsi_hostSEQNUM=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=changeDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0SUBSYSTEM=scsiSDEV_MEDIA_CHANGE=1DEVTYPE=scsi_deviceDRIVER=sdMODALIAS=scsi:t-0x00SEQNUM=1331uevent '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=addDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdbSUBSYSTEM=blockMAJOR=8MINOR=16DEVNAME=sdbDEVTYPE=diskSEQNUM=1332uevent '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=addDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0/host4/target4:0:0/4:0:0:0/block/sdb/sdb1SUBSYSTEM=blockMAJOR=8MINOR=17DEVNAME=sdb1DEVTYPE=partitionSEQNUM=1333uevent 'add' from '/devices/virtual/bdi/8:16'.ACTION=addDEVPATH=/devices/virtual/bdi/8:16SUBSYSTEM=bdiSEQNUM=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=removeDEVPATH=/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:0SUBSYSTEM=bsgMAJOR=253MINOR=1DEVNAME=bsg/4:0:0:0SEQNUM=1335uevent '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=removeDEVPATH=/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:0SUBSYSTEM=scsi_deviceSEQNUM=1336uevent '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=removeDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5/4-5:1.0SUBSYSTEM=usbDEVTYPE=usb_interfaceDEVICE=/proc/bus/usb/004/004PRODUCT=781/5590/100TYPE=0/0/0INTERFACE=8/6/80MODALIAS=usb:v0781p5590d0100dc00dsc00dp00ic08isc06ip50SEQNUM=1344uevent 'remove' from '/devices/pci0000:00/0000:00:13.2/usb4/4-5'.ACTION=removeDEVPATH=/devices/pci0000:00/0000:00:13.2/usb4/4-5SUBSYSTEM=usbMAJOR=189MINOR=387DEVNAME=bus/usb/004/004DEVTYPE=usb_deviceDEVICE=/proc/bus/usb/004/004PRODUCT=781/5590/100TYPE=0/0/0BUSNUM=004DEVNUM=004SEQNUM=1345uevent 'remove' from '/host4/target4:0:0'.ACTION=removeDEVPATH=/host4/target4:0:0SUBSYSTEM=scsiDEVTYPE=scsi_targetSEQNUM=1346
0 0
原创粉丝点击