在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<abbr id="27omo"></abbr>

<menu id="27omo"><dl id="27omo"></dl></menu>
    • <label id="27omo"><tt id="27omo"></tt></label>

      博客專欄

      EEPW首頁(yè) > 博客 > 監(jiān)聽容器中的文件系統(tǒng)事件

      監(jiān)聽容器中的文件系統(tǒng)事件

      發(fā)布人:電子禪石 時(shí)間:2024-09-18 來源:工程師 發(fā)布文章
      基本概念

      Linux 文件系統(tǒng)事件監(jiān)聽:應(yīng)用層的進(jìn)程操作目錄或文件時(shí),會(huì)觸發(fā) system call,此時(shí),內(nèi)核中的 notification 子系統(tǒng)把該進(jìn)程對(duì)文件的操作事件上報(bào)給應(yīng)用層的監(jiān)聽進(jìn)程(稱為 listerner)。

      dnotify:2001 年的 kernel 2.4 版本引入,只能監(jiān)控 directory,采用的是 signal 機(jī)制來向 listener 發(fā)送通知,可以傳遞的信息很有限。

      inotify:2005 年在 kernel 2.6.13 中亮相,除了可以監(jiān)控目錄,還可以監(jiān)聽普通文件,inotify 擯棄了 signal 機(jī)制,通過 event queue 向 listener 上傳事件信息。

      fanotify:kernel 2.6.36 引入,fanotify 的出現(xiàn)解決了已有實(shí)現(xiàn)只能 notify 的問題,允許 listener 介入并改變文件事件的行為,實(shí)現(xiàn)從“監(jiān)聽”到“監(jiān)控”的跨越。

      本文主要介紹如何通過 inotify 和 fanotify 監(jiān)聽容器中的文件系統(tǒng)事件。

      Inotify基本介紹

      inotify(inode[1] notify)是 Linux 內(nèi)核中的一個(gè)子系統(tǒng),由 John McCutchan[2] 創(chuàng)建,用于監(jiān)視文件系統(tǒng)事件。它可以在文件或目錄發(fā)生變化時(shí)通知應(yīng)用程序,例如,監(jiān)聽文件的創(chuàng)建、修改或刪除事件。inotify 可以用于自動(dòng)更新文件系統(tǒng)視圖、重新加載配置文件,記錄文件改變歷史等場(chǎng)景。

      Inotify 的工作流程如下:

      1. 用戶通過系統(tǒng)調(diào)用(如:write、read)操作文件;

      2. 內(nèi)核將文件系統(tǒng)事件保存到 fsnotify_group 的事件隊(duì)列中;

      3. 喚醒等待 inotify 的進(jìn)程(listener);

      4. 進(jìn)程通過 fd 從內(nèi)核隊(duì)列讀取 inotify 事件。

      圖片

      其中,inotify_event_info 的定義如下:

      c

      mask 標(biāo)記具體的文件操作事件。

      API 介紹

      Inotify 可以用來監(jiān)聽單個(gè)文件,也可以用來監(jiān)聽目錄。當(dāng)監(jiān)聽的是目錄時(shí),inotify 除了生成目錄的事件,還會(huì)生成目錄中文件的事件。

      注意:當(dāng)使用 inotify 監(jiān)聽目錄時(shí),并不會(huì)遞歸監(jiān)聽子目錄中的文件,如果需要得到這些事件,需要手動(dòng)指定監(jiān)聽這些文件。對(duì)于很大的目錄樹,這個(gè)過程將花費(fèi)大量時(shí)間。

      參考:inotify.7[3]

      • inotify_init(void)

      初始化 inotify 實(shí)例,返回文件描述符,用于內(nèi)核向用戶態(tài)程序傳輸監(jiān)聽到的 inotify 事件。函數(shù)聲明為:

      c

      內(nèi)核同時(shí)提供了int inotify_init1(int flags),flags 的可選值如下:

      c

      可以通過 OR 指定多個(gè)flag,當(dāng)flags=0等價(jià)于int inotify_init(void)。

      • inotify_add_watch

      添加需要監(jiān)聽的目錄或文件(watch list),可以添加新的路徑,也可以是已經(jīng)添加過的路徑。fd 是inotify_init返回的文件描述符,mask 指定需要監(jiān)聽的事件類型,通過 OR 指定多個(gè)事件。返回值是當(dāng)前路徑的wd(watch descriptor),可用于移除對(duì)該路徑的監(jiān)聽。

      函數(shù)聲明為:

      c

      Inotify 支持監(jiān)聽的事件包括:

      c
      • inotify_rm_watch

      移除被監(jiān)聽的路徑。fd 是inotify_init返回的文件描述符,wd 是inotify_add_watch返回的監(jiān)聽文件描述符。

      函數(shù)聲明為:

      c
      實(shí)例

      以下是基于 Rust 語(yǔ)言實(shí)現(xiàn)的實(shí)例:

      rust
      use nix::{    poll::{poll, PollFd, PollFlags},    sys::inotify::{AddWatchFlags, InitFlags, Inotify, InotifyEvent},};use signal_hook::{consts::SIGTERM, low_level::pipe};use std::os::unix::net::UnixStream;use std::{env, io, os::fd::AsRawFd, path::PathBuf};fn main() -> io::Result<()> {    let args: Vec<String> = env::args().collect();    if args.len() < 2 {        eprintln!("Usage: {} <path>", args[0]);        std::process::exit(1);    }    let path = PathBuf::from(&args[1]);    // 初始化 inotify,得到 fd    let inotify_fd = Inotify::init(InitFlags::empty())?;    // 添加被監(jiān)聽的目錄或文件,指定需要監(jiān)聽的事件    let wd = inotify_fd.add_watch(        &path,        AddWatchFlags::IN_ACCESS | AddWatchFlags::IN_OPEN | AddWatchFlags::IN_CREATE,    )?;    let (read, write) = UnixStream::pair()?;    // 注冊(cè)用于處理信號(hào)的 pipe    if let Err(e) = pipe::register(SIGTERM, write) {        println!("failed to set SIGTERM signal handler {e:?}");    }    let mut fds = [        PollFd::new(inotify_fd.as_raw_fd(), PollFlags::POLLIN),        PollFd::new(read.as_raw_fd(), PollFlags::POLLIN),    ];    loop {        match poll(&mut fds, -1) {            Ok(polled_num) => {                if polled_num <= 0 {                    eprintln!("polled_num <= 0!");                    break;                }                if let Some(flag) = fds[0].revents() {                    if flag.contains(PollFlags::POLLIN) {                        // 得到 inotify 事件,進(jìn)行處理                        let events = inotify_fd.read_events()?;                        for event in events {                            handle_event(event)?;                        }                    }                }                if let Some(flag) = fds[1].revents() {                    if flag.contains(PollFlags::POLLIN) {                        println!("received SIGTERM signal");                        break;                    }                }            }            Err(e) => {                if e == nix::Error::EINTR {                    continue;                }                eprintln!("Poll error {:?}", e);                break;            }        }    }    inotify_fd.rm_watch(wd)?;    Ok(())}fn handle_event(event: InotifyEvent) -> io::Result<()> {    let file_name = match event.name {        Some(name) => name,        None => return Ok(()),    };    let event_mask = event.mask;    let kind = if event_mask.contains(AddWatchFlags::IN_ISDIR) {        "directory"    } else {        "file"    };    println!(        "{} {} was {:?}.",        kind,        file_name.to_string_lossy(),        event_mask    );    Ok(())}

      編譯&測(cè)試:

      shell
      cargo build./target/debug/inotify test

      圖片

      可以看到,inotify 不會(huì)遞歸監(jiān)聽二級(jí)目錄下的文件dir1/file2.txt。

      經(jīng)測(cè)試,Inotify 可以直接監(jiān)聽容器 rootfs 下的目錄:

      shell
      nerdctl run --rm -it golang./target/debug/inotify /run/containerd/io.containerd.runtime.v2.task/default/CONTAINERD_ID/rootfs

      圖片

      Fanotify基本介紹

      Inotify 能夠監(jiān)聽目錄和文件的事件,但這種 notifiation 機(jī)制也存在局限:inotify 只能通知用戶態(tài)進(jìn)程觸發(fā)了哪些文件系統(tǒng)事件,而無法進(jìn)行干預(yù),典型的應(yīng)用場(chǎng)景是殺毒軟件。

      Fanotify[4] 的出現(xiàn)就是為了解決這個(gè)問題,同時(shí)允許遞歸監(jiān)聽目錄下的子目錄和文件。

      Fanotify 的工作流程如下:

      1. 用戶通過系統(tǒng)調(diào)用(如:write、read)操作文件;

      2. 內(nèi)核將文件系統(tǒng)事件發(fā)送到 fsnotify_group 的事件隊(duì)列中;

      3. 喚醒等待 fanotify 事件的進(jìn)程(listener);

      4. 進(jìn)程通過 fd 從內(nèi)核隊(duì)列讀取 fanotify 事件;

      5. 如果是 FAN_OPEN_PERM 和 FAN_ACCESS_PERM 監(jiān)聽類型,進(jìn)程需要通過 write 把許可信息(允許 or 拒絕)寫回內(nèi)核;

      6. 內(nèi)核根據(jù)許可信息決定是否繼續(xù)完成該文件系統(tǒng)事件。

      監(jiān)監(jiān)聽容器中的文件系統(tǒng)事件 - abin在路上 - 博客園 (cnblogs.com)

      *博客內(nèi)容為網(wǎng)友個(gè)人發(fā)布,僅代表博主個(gè)人觀點(diǎn),如有侵權(quán)請(qǐng)聯(lián)系工作人員刪除。



      關(guān)鍵詞: fanotify

      技術(shù)專區(qū)

      關(guān)閉