2015年11月9日 星期一

如何監測 USB uevent ?

尚書:「非知之艱,行之惟艱」

The umond (uevent monitor) is used to catch two plug/unplug messages for calling start/stop USB service daemon at the right timing.

How to about Uevent:

The umond (uevent monitor) is a netlink socket base program, and it poll netlink socket interface from driver to put needed events a buffer cache, then search the unique identifier string to catch add/remove event in order to call start/stop USB service daemon at the proper timing. The most valuable is exactly mount per file system type, even multiple partitions, thus, not to need protect many same kinds of events(adds, removes) to damage the mounting process, and so that to remove the side effects of race condition of multiple event calling.






原始程式

/**
 * File name: umond.c
 *      Uevent Monitor Daemon for USB application SAMBA FTPD
 *      To poll netlink socket event and filter those of add/remove message.
 *
 * Author:
 *      created by Tom Ho <bq101202@gmail.com>  09-02-2013
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/netlink.h>
#define UEVENT_BUFFER_SIZE 1024


static struct pollfd * init_uevt_sock(void)
{
    struct sockaddr_nl nls;
    struct pollfd pfd;
    char *loc;
    const int buffersize = 16 * 1024;

    memset(&nls, 0, sizeof(nls));
    nls.nl_family = AF_NETLINK;
    nls.nl_pid = getpid();
    nls.nl_groups = -1;

    pfd.events = POLLIN;
    pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (pfd.fd == -1) {
        printf("Not root\n");
        exit(1);
    }

    setsockopt(pfd.fd, SOL_SOCKET, SO_RCVBUFFORCE, &buffersize, sizeof(buffersize));
    if(bind(pfd.fd, (struct sockaddr *) &nls, sizeof(struct sockaddr_nl)))
    {
        printf("bind failed\n");
        exit(1);
    }
    return &pfd;
}

int main(int argc, char *argv[])
{
    struct pollfd *pfdClient = init_uevt_sock();
    char buf_cache[UEVENT_BUFFER_SIZE*2] = {0};
    char *loc;
    char *loc1;
    char *loc2;

    while (-1 != poll(pfdClient, 1, -1)) {
        memset(buf_cache, 0 ,sizeof(buf_cache));
        int i, len = recv(pfdClient->fd, buf_cache, sizeof(buf_cache), MSG_DONTWAIT);
        if (len == -1) {
            printf("recv\n");
            exit(1);
        }
        i = 0;
        while (i < len) {
/* Tom: got idea of a policy of unique distinguishable approach for hot-plug messages */
            loc = strstr(buf_cache+i, "add@/devices/virtual/bdi/8:0");
            if(loc != NULL) {
                    printf("ADDed\n");
                    sleep (7);
                    system ("/etc/init.d/samba stop;sleep 1;/etc/init.d/ftpd stop");
                    sleep (1);
                    system ("/etc/init.d/samba boot;sleep 1;/etc/init.d/ftpd boot");
            }
            loc1 = strstr(buf_cache+i, "remove@/host");
            loc2 = strstr(buf_cache+i, "remove@/devices/virtual/bdi/8:0");
            if(loc2) {
                    printf("REMOVEd\n");
                    sleep (6);
                    // Here added handling codes to deal with specififed application

            }
/* Tom: we need to suppress it and adopt another policy to dael with uncontrolled cases.
            loc = strstr(buf_cache+i, "=add");
            if(loc != NULL) {
                    //  too many messages to distinguish
            }
*/
/* Tom: we need to suppress it and adopt another policy to deal with uncontrolled cases.
            loc = strstr(buf_cache+i, "=remove");
            if(loc != NULL) {
                    //  too many messages to distinguish
            }
*/
            i += strlen(buf_cache+i) + 1;
        }
    }
    printf("\n");
    return 0;


}

沒有留言:

張貼留言