如何将监听器附加到 sysfs 文件?

如何将监听器附加到 sysfs 文件?

如何监视sysfs文件更改(例如/sys/class/net/eth0/statistics/operstate)并在内容更改上执行命令?

  • inotify不起作用sysfs
  • 我不想投票。我想设置一个带有回调例程的监听器一次

答案1

我还没有阅读填充的源代码operstate,但通常,读取 sysfs 中的文件会在内核端执行一些代码,返回您正在读取的字节。所以,如果你没有阅读operstate,它就没有“状态”。该值不存储在任何地方。

如何监视 sysfs 文件更改

由于这些实际上不是文件,因此不存在“更改”的概念。

可能有更好的方法来实现您想要的!netlink被设计具体来说用于监控网络状态的任务;它是易于接口。例如,这个经过最小修改的示例代码man 7 netlink可能已经解决了您的问题:

       struct sockaddr_nl sa;

       memset(&sa, 0, sizeof(sa));
       sa.nl_family = AF_NETLINK;
       // Link state change notifications:
       sa.nl_groups = RTMGRP_LINK;

       fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
       bind(fd, (struct sockaddr *) &sa, sizeof(sa));

一般来说,如果这不是关于以太网级别的连接,而是与某些 IP 网络(或互联网)的连接,那么 systemd/NetworkManager 就是您在现代系统上使用的路径。

答案2

正如善良的穆勒已经解释过的那样,你不能监视器 sysfs文件,因为它们是虚拟文件系统的一部分,并且不像普通文件

我最终把自己降到了一些C,虽然未经测试而且看起来不太好看,但还是一个拙劣的作品这个的片段netlink,作为来自和 的更广泛的例子rnetlink:

./realtimnetlink
Monitoring
RTM NEWLINK enp12s0 DOWN
RTM NEWLINK enp12s0 UP
RTM NEWLINK eth10 DOWN
RTM NEWADDR eth10
RTM NEWLINK eth10 UP

编译通过gcc -o foo foo.c

#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <sys/socket.h>
#include <linux/rtnetlink.h>
#include <net/if.h>

#define E_PRINT(f_, ...) fprintf(stderr, ("ERROR NetLink: %s" f_ "\n"), ##__VA_ARGS__)

int open_netlink()
{
    int soc; // fd
    struct sockaddr_nl sa;

    memset(&sa, 0, sizeof(sa));
    sa.nl_family = AF_NETLINK;
    sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
    soc = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
    if (soc < 0) {
        perror("INIT socket: ");
        return -1;
    }
    if (bind(soc, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
        perror("INIT bind_socket:");
        return -1;
    }
    return soc;
}
int event_read(
    int sockint,
    int (*msg_handler)(struct nlmsghdr *)
) {
    int status;
    int ret = 0;
    char buf[4096];
    struct iovec iov = { buf, sizeof buf };
    struct sockaddr_nl snl;
    struct msghdr msg = {
        (void*)&snl,
        sizeof snl,
        &iov, 1, NULL, 0, 0
    };
    struct nlmsghdr *hdr;

    status = recvmsg(sockint, &msg, 0);

    if (status < 0) {
        /* Socket non-blocking so bail out once we have read everything */
        if (errno == EWOULDBLOCK || errno == EAGAIN)
            return ret;
        /* Anything else is an error */
        E_PRINT("recvmsg: %d", "EVT_READ", status);
        perror("ERROR read_netlink: ");
        return status;
    } else if (status == 0) {
        E_PRINT("recvmsg: EOF", "EVT_READ");
    }

    /* We need to handle more than one message per 'recvmsg' */
    for (
        hdr = (struct nlmsghdr *) buf;
        NLMSG_OK (hdr, (unsigned int)status);
        hdr = NLMSG_NEXT (hdr, status)
    ) {
        /* Finish reading */
        if (hdr->nlmsg_type == NLMSG_DONE)
            return ret;

        /* Message is some kind of error */
        if (hdr->nlmsg_type == NLMSG_ERROR) {
            E_PRINT("Decode to be done", "EVT_READ");
            return -1;
        }
        /* Call message handler */
        if (msg_handler) {
            ret = (*msg_handler)(hdr);
            if (ret < 0) {
                E_PRINT("msg_handler: %d", "EVT_READ", ret);
                return ret;
            }
        } else {
            E_PRINT("NULL message handler", "EVT_READ");
            return -1;
        }
    }
    return ret;
}
static int msg_handler(struct nlmsghdr *msg)
{
    struct ifinfomsg *ifi = NLMSG_DATA(msg);
    struct ifaddrmsg *ifa = NLMSG_DATA(msg);
    char ifname[1024];

    switch (msg->nlmsg_type) {
    case RTM_NEWADDR:
        if_indextoname(ifa->ifa_index, ifname);
        printf("RTM NEWADDR %s\n", ifname);
        break;
    case RTM_DELADDR:
        if_indextoname(ifa->ifa_index, ifname);
        printf("RTM DELADDR %s\n", ifname);
        break;
    case RTM_NEWLINK:
        if_indextoname(ifi->ifi_index, ifname);
        printf("RTM NEWLINK %s %s\n",
            ifname,
            (ifi->ifi_flags & IFF_UP) ? "UP" : "DOWN"
        );
        break;
    case RTM_DELLINK:
        if_indextoname(ifi->ifi_index, ifname);
        printf("RTM DELLINK %s\n", ifname);
        break;
    default:
        fprintf(stderr,
            "RTM UNKNOWN nlmsg_type %d\n",
            msg->nlmsg_type
        );
        break;
    }
    return 0;
}

int main(void)
{
    int nls = open_netlink();
    if (nls < 0) {
        E_PRINT("Open Error!", "INIT");
        return 1;
    }
    fprintf(stderr, "Monitoring\n");
    while (1)
        event_read(nls, msg_handler);
    return 0;
}

相关内容