inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败

Posted

技术标签:

【中文标题】inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败【英文标题】:inotify_add_watch fails on /sys/class/net/eth0/operstate 【发布时间】:2014-10-31 10:25:38 【问题描述】:

我在 Linux 中使用了 inotify,以便在网络接口链接更改时引发事件。每当接口链接更改时,/sys/class/net/eth40/operstate/ 文件就会被修改。但是在下面的代码sn-p中,即使文件被修改,读取功能仍然处于阻塞状态。

#include <stdio.h>
#include <sys/inotify.h>
#include <stdlib.h>
#include <limits.h>
#include <signal.h>
#define FILE_TO_WATCH "/sys/class/net/eth40/operstate"
#define EVENT_SIZE (sizeof (struct inotify_event))
#define EVENT_BUFFER_LENGTH (1024 * EVENT_SIZE + NAME_MAX + 1)

void print_event(struct inotify_event *event) 

    int ret = 0;
    if (event->mask & IN_CREATE)
        printf("file created in directory\n");
    if (event->mask & IN_DELETE)
        printf("file deleted in directory\n");
    if (event->mask & IN_ACCESS)
        printf("file accessed\n");
    if (event->mask & IN_CLOSE)
        printf("file closed after reading or writing \n");
    if (event->mask & IN_OPEN)
        printf("file opened\n");

    if (event->len)
        printf("name: %s\n", event->name);


int main(int argc, char** argv)

    int notify_fd;
    int watch_fd;
    long input_len;
    char *ptr;
    char buffer[EVENT_BUFFER_LENGTH];
    struct inotify_event *event;

    notify_fd = inotify_init();
    if (notify_fd < 0) 
        perror("cannot init inotify");
        exit(EXIT_FAILURE);
    
    printf("done1\n");
    watch_fd = inotify_add_watch(notify_fd,FILE_TO_WATCH,IN_ACCESS|IN_MODIFY);
    if (watch_fd < 0) 
        perror("cannot add file");
        exit(EXIT_FAILURE);
    
    printf("done2\n");
    while (1) 
        input_len = read(notify_fd, buffer, EVENT_BUFFER_LENGTH);
        if (input_len <= 0) 
            perror("error reading from inotify fd");
            exit(EXIT_FAILURE);
        
        printf("done3\n");
        ptr = buffer;
        while (ptr < buffer + input_len) 
            event = (struct inotify_event *) ptr;
            print_event(event);
            ptr += sizeof (struct inotify_event) +event->len;
        
    

我错过了什么吗?

【问题讨论】:

【参考方案1】:

/sys 不是一个普通的文件系统,而是一个特殊的内存文件系统,叫做sysfs

引用kernel developer:

inotify 不会也不会在 sysfs 上工作。或procfs。或开发人员。 或任意数量的网络文件系统。不管一个人多么努力 可能希望它工作,这根本不可行。

对于网络链接事件,您可以使用 rtnetlink,虽然这样的内容几乎没有文档记录,但这里有一个起点示例,将向您展示链接(和其他一些)事件,您必须弄清楚哪些事件/flags 和与您的特定情况相关的类似内容。

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <asm/types.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/if.h>
#include <linux/rtnetlink.h>

#define ENTRY(x) x, #x
struct 
    unsigned flag;
    const char *name;
 ifi_flag_map[] = 
    ENTRY(IFF_UP),
    ENTRY(IFF_BROADCAST),
    ENTRY(IFF_DEBUG),
    ENTRY(IFF_LOOPBACK),
    ENTRY(IFF_POINTOPOINT),
    ENTRY(IFF_NOTRAILERS),
    ENTRY(IFF_RUNNING),
    ENTRY(IFF_NOARP),
    ENTRY(IFF_PROMISC),
    ENTRY(IFF_ALLMULTI),
    ENTRY(IFF_MASTER),
    ENTRY(IFF_SLAVE),
    ENTRY(IFF_MULTICAST),
    ENTRY(IFF_PORTSEL),
    ENTRY(IFF_AUTOMEDIA),
    ENTRY(IFF_DYNAMIC),
    ENTRY(IFF_LOWER_UP),
    ENTRY(IFF_DORMANT),
    ENTRY(IFF_ECHO),
;
struct 
    unsigned type;
    const char *name;
 nlmrt_type_map[] = 
    ENTRY(RTM_NEWLINK ),
    ENTRY(RTM_DELLINK),
    ENTRY(RTM_GETLINK),
    ENTRY(RTM_SETLINK),
    ENTRY(RTM_NEWADDR ),
    ENTRY(RTM_DELADDR),
    ENTRY(RTM_GETADDR),
    ENTRY(RTM_NEWROUTE    ),
    ENTRY(RTM_DELROUTE),
    ENTRY(RTM_GETROUTE),
    ENTRY(RTM_NEWNEIGH    ),
    ENTRY(RTM_DELNEIGH),
    ENTRY(RTM_GETNEIGH),
    ENTRY(RTM_NEWRULE ),
    ENTRY(RTM_DELRULE),
    ENTRY(RTM_GETRULE),
    ENTRY(RTM_NEWQDISC    ),
    ENTRY(RTM_DELQDISC),
    ENTRY(RTM_GETQDISC),
    ENTRY(RTM_NEWTCLASS   ),
    ENTRY(RTM_DELTCLASS),
    ENTRY(RTM_GETTCLASS),
    ENTRY(RTM_NEWTFILTER  ),
    ENTRY(RTM_DELTFILTER),
    ENTRY(RTM_NEWACTION   ),
    ENTRY(RTM_DELACTION),
    ENTRY(RTM_GETACTION),
    ENTRY(RTM_NEWPREFIX   ),
    ENTRY(RTM_GETMULTICAST ),
    ENTRY(RTM_GETANYCAST  ),
    ENTRY(RTM_NEWNEIGHTBL ),
    ENTRY(RTM_GETNEIGHTBL ),
    ENTRY(RTM_SETNEIGHTBL),
    ENTRY(RTM_NEWNDUSEROPT ),
    ENTRY(RTM_NEWADDRLABEL ),
    ENTRY(RTM_DELADDRLABEL),
    ENTRY(RTM_GETADDRLABEL),
    ENTRY(RTM_GETDCB ),
    ENTRY(RTM_SETDCB),
    ENTRY(RTM_NEWNETCONF ),
    ENTRY(RTM_GETNETCONF ),
    ENTRY(RTM_NEWMDB ),
    ENTRY(RTM_DELMDB ),
    ENTRY(RTM_GETMDB ),
;

void print_type(unsigned type)

    size_t i;

    for (i = 0; i < sizeof nlmrt_type_map/sizeof nlmrt_type_map[0]; i++) 
        if (type == nlmrt_type_map[i].type) 
            printf("\t\tMsg Type: %s\n", nlmrt_type_map[i].name);
            return;
        
    

    printf("\t\tMsg Type: unknown(%d)\n", type);

void print_flags(unsigned flags, unsigned change)

    size_t i;

    printf("\t\tflags: ");

    for (i = 0; i < sizeof ifi_flag_map/sizeof ifi_flag_map[0]; i++) 
        if (flags & ifi_flag_map[i].flag) 
            if (change & ifi_flag_map[i].flag) 
                printf("%s(C) ", ifi_flag_map[i].name);
             else 
                printf("%s ", ifi_flag_map[i].name);
            
        
    
    puts("");

oid read_msg(int fd)

    int len;
    char buf[4096];
    struct iovec iov =  buf, sizeof(buf) ;
    struct sockaddr_nl sa;
    struct msghdr msg =  (void *)&sa, sizeof(sa), &iov, 1, NULL, 0, 0 ;
    struct nlmsghdr *nh;

    len = recvmsg(fd, &msg, 0);
    if(len == -1) 
        perror("recvmsg");
        return;
    

    for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
         nh = NLMSG_NEXT (nh, len)) 
         struct ifinfomsg *ifimsg;
        /* The end of multipart message. */
         printf("netlink message: len = %u, type = %u, flags = 0x%X, seq = %u, pid = %u\n",
            nh->nlmsg_len,
            nh->nlmsg_type,
            nh->nlmsg_flags,
            nh->nlmsg_seq,
            nh->nlmsg_pid);

        if (nh->nlmsg_type == NLMSG_DONE)
            return;

       if (nh->nlmsg_type == NLMSG_ERROR) 
            continue;
       

       ifimsg = NLMSG_DATA(nh);
       printf("\tifi_family = %u, ifi_type = %u, ifi_index = %u, ifi_flags = 0x%X, ifi_change = 0x%X\n",
               ifimsg->ifi_family ,
               ifimsg->ifi_type ,
               ifimsg->ifi_index ,
               ifimsg->ifi_flags ,
               ifimsg->ifi_change);
       print_type(nh->nlmsg_type);
       print_flags(ifimsg->ifi_flags, ifimsg->ifi_change);
    

int main(int argc, char *argv[])

    struct sockaddr_nl sa;
    int fd;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR;

    fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if(fd == -1) 
        perror("socket");
        return 1;
    

    if(bind(fd, (struct sockaddr *) &sa, sizeof(sa)) == -1) 
        perror("bind");
        return 1;
    
    for(;;) 
        read_msg(fd);
    

    return 0;

【讨论】:

您能否建议我使用其他方法来监控 NIC 端口上的网络链接事件。 有什么方法可以在c中实现windows中的网络链接事件吗? @MujtabaMohd 可能。您可以在检查是否已在 *** 上询问或检查 MSDN 文档以获得简单的解决方案后提出一个新问题。

以上是关于inotify_add_watch 在 /sys/class/net/eth0/operstate 上失败的主要内容,如果未能解决你的问题,请参考以下文章

为啥需要使用 inotify_add_watch() 调用 read() 两次

inotify_add_watch 失败,没有这样的文件或目录

推送到 bitbucket 时出现错误“inotify_add_watch”

inotify,inotify_add_watch() 监控多个目录,c++

inotify_add_watch 相对于 O_PATH dirfd

Docker 守护进程无法启动:inotify_add_watch: no such file or directory