3 KiB
3 KiB
sequenceDiagram
%%{init: { 'theme': 'default', 'themeVariables': {
'primaryColor': '#ff0000',
'nodeTextColor': '#ffffff',
'edgeLabelBackground': '#f0f0f0'
}}}%%
autonumber
participant Watcher as Демон-наблюдатель
participant Kernel as Ядро (fanotify)
participant Editor as Процесс-редактор (PID X)
participant FS as Файловая система (целевой каталог/файл)
participant Ep as epoll
participant Pfd as pidfd(PID X)
participant Map as Карта соответствий (в памяти)
participant ChLog as Журнал изменений
Note over Watcher: Инициализация
Watcher->>Kernel: fanotify_init(PRE_CONTENT|NONBLOCK|CLOEXEC, O_RDONLY|O_CLOEXEC|O_LARGEFILE)
Watcher->>Kernel: fanotify_mark(ADD|ONLYDIR, EVENT_ON_CHILD | OPEN[_EXEC]_PERM | OPEN | CLOSE_WRITE, watchDir)
Watcher->>Ep: add(fanotify_fd, tag=FAN)
Note over Editor: Запрос доступа к файлу
Editor->>FS: open(target, O_RDONLY/O_RDWR/EXEC)
FS-->>Kernel: системный вызов доступа
Kernel-->>Watcher: PERM-событие (+fd, mask, pid)
Note over Watcher: Сбор контекста
Watcher->>FS: fstat(fd) → (inode, dev)
FS-->>Watcher: inode, dev
Watcher->>Watcher: readlink(/proc/self/fd/FD) → file_path_open
Watcher->>Watcher: read /proc/PID/comm → proc_name
Watcher->>Watcher: read /proc/PID/status(Uid:) → RUID
Watcher->>Watcher: read /proc/PID/loginuid → UID(loginuid)
%% Кладём связку
Watcher->>Map: PUT key=(PID,inode,dev), val={proc_name, RUID, UID, file_path_open, changed=false}
Note over Map: Добавлена связка key=(PID,inode,dev)
%% pidfd и epoll
Watcher->>Pfd: pidfd_open(PID, flags=0)
Pfd-->>Watcher: pidfd
Watcher->>Ep: add(pidfd, tag=PID, events=IN|HUP|RDHUP|ERR)
%% Разрешаем доступ
Watcher->>Kernel: fanotify_response{fd, FAN_ALLOW}
Watcher->>FS: close(fd)
Note over Editor: Работа с файлом
Editor->>FS: write(...)
Editor->>FS: close()
Kernel-->>Watcher: CLOSE_WRITE (+fd)
Note over Watcher: Фиксация изменения
Watcher->>FS: fstat(fd) → (inode, dev)
FS-->>Watcher: inode, dev
Watcher->>Map: GET key=(PID,inode,dev)
Map-->>Watcher: {…}
Watcher->>Map: SET changed=true
Watcher->>FS: close(fd)
Note over Editor: Завершение процесса
Editor->>Editor: exit()
Pfd-->>Ep: EPOLLIN/HUP (процесс завершён)
Ep-->>Watcher: событие(tag=PID)
%% Пишем журнал и чистим
Watcher->>Map: GET_ALL where pid=PID
Map-->>Watcher: список записей
Watcher->>ChLog: APPEND для changed=true → {proc=proc_name, file=file_path_open, uid=UID(loginuid), ruid=RUID}
Watcher->>Ep: remove(pidfd); Watcher->>Pfd: close(pidfd)
Watcher->>Map: DELETE_ALL where pid=PID
Note over Map: Удалены все связки для PID