如何监视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;
}