sysfsファイルにリスナーを関連付ける方法は?

sysfsファイルにリスナーを関連付ける方法は?

sysfsファイルの変更(例:)を監視/sys/class/net/eth0/statistics/operstateし、コンテンツの変更に対してコマンドを実行するにはどうすればよいですか?

  • inotify動作しませんsysfs
  • 私は投票したくありません。コールバックルーチンを使用してリスナーを一度設定したいと思います。

答え1

私はpaddingのソースコードを読みませんでしたが、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;
}

関連情報