Como manter monitorações confiáveis ​​em arquivos editados com o inotify?

Como manter monitorações confiáveis ​​em arquivos editados com o inotify?

Gostaria de monitorar um arquivo com inotifye acionar algum código quando alguém altera o conteúdo ( IN_MODIFYou IN_CLOSE_WRITE), mas estou tendo problemas onde inotifypara de retornar eventos quando os usuários editam o arquivo com sua ferramenta favorita. O arquivo deve ser simples (linha única, sem espaços, no máximo 20 caracteres). Prefiro não restringir seu uso, mas não sei como lidar com diferentes situações.

Estou usando inotifye estes são os eventos que recebo quando vários aplicativos editam o arquivo:

Ação inotify Eventos
touch file IN_OPEN
echo "data" > file IN_MODIFY, IN_OPEN, IN_ACCESS, entãoIN_CLOSE_NOWRITE
nano file(em aberto) IN_OPEN
nano file(sobre ^O) IN_MODIFY, IN_CLOSE_WRITE, IN_OPEN,IN_ACCESS
vim file(em aberto) IN_OPEN,IN_CLOSE_NOWRITE
vim file(sobre :w) IN_MOVE_SELF, IN_ATTRIB, então os eventos param de vir deste arquivo
gedit file(em aberto) IN_OPEN, IN_CLOSE_NOWRITE,IN_ACCESS
gedit file(ao salvar) IN_OPEN, IN_CLOSE_WRITE, IN_ATTRIB, então os eventos param de vir deste arquivo
mv newfile file IN_ATTRIB, então os eventos param de vir deste arquivo

A certa altura, pensei ter visto gedito gatilho também disparar IN_DELETE_SELFantes de ficar em silêncio.

No caso em que um usuário usa vime gedit, paro de receber inotifyeventos depois que o usuário termina as edições. Como devo lidar com isso?

A única coisa que vejo em comum é o IN_ATTRIBevento. Suspeito que quando receber o IN_ATTRIBevento, devo fazer inotify_rm_watch()isso wde depois recriar um novo inotify_add_watch()com base no mesmo caminho. Mas essa é a abordagem correta?

Outra opção poderia ser observar o diretório pai. O nome do arquivo afetado está incluído no arquivo inotify_event::namee, portanto, eu poderia filtrar o arquivo de interesse e acionar qualquer um IN_MODIFYou IN_CLOSE_WRITEonde namecorresponda ao meu arquivo de interesse.

Responder1

Como menciona ikkachu, alguns editores criam um novo arquivo e depois substituem o original, alterando o inode. Isso significa que todos os relógios no descritor de relógio original expirarão.

A resposta é examinar o diretório pai e verificar se há alterações em qualquer arquivo com o nome de destino. Algo assim:

namespace fs = std::filesystem;
fs::path path = "./file1";
assert( !path.is_directory() );

int fd = inotify_init();

int wd = inotify_add_watch(
    fd, 
    path.parent_path().c_str(),
    IN_MODIFY | IN_CREATE | IN_CLOSE_WRITE
);  

...

inotify_event event;
read(fd, &event, BUF_SIZE);

if (wd == event->wd && path.filename() == event->name) {
    emit_file_changed();
}

Esses eventos ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE) capturam as técnicas que tentei acima ( touch, echo "" >, vim, nano, gedit). Aposto que também poderia capturar links simbólicos alterados com eles.

Responder2

Ou você pode usar o fatrace, que é muito mais rápido e não apresenta esses problemas, por exemplo, algo assim:

fatrace --timestamp --filter='WD<>+'

informação relacionada