¿Cómo mantener de manera confiable la vigilancia de archivos editados con inotify?

¿Cómo mantener de manera confiable la vigilancia de archivos editados con inotify?

Me gustaría monitorear un archivo con inotifyy activar algún código cuando alguien cambia el contenido ( IN_MODIFYo IN_CLOSE_WRITE), pero tengo problemas que inotifydejan de devolver eventos cuando los usuarios editan el archivo con su herramienta favorita. El archivo debe ser simple (una sola línea, sin espacios, máximo 20 caracteres). Preferiría no restringir su uso, pero no estoy seguro de cómo manejar diferentes situaciones.

Estoy usando inotifyy estos son los eventos que recibo cuando varias aplicaciones editan el archivo:

Acción notificar eventos
touch file IN_OPEN
echo "data" > file IN_MODIFY, IN_OPEN, IN_ACCESS, entoncesIN_CLOSE_NOWRITE
nano file(en abierto) IN_OPEN
nano file(en ^O) IN_MODIFY, IN_CLOSE_WRITE, IN_OPEN,IN_ACCESS
vim file(en abierto) IN_OPEN,IN_CLOSE_NOWRITE
vim file(en :w) IN_MOVE_SELF, IN_ATTRIB, entonces los eventos dejan de provenir de este archivo
gedit file(en abierto) IN_OPEN, IN_CLOSE_NOWRITE,IN_ACCESS
gedit file(al guardar) IN_OPEN, IN_CLOSE_WRITE, IN_ATTRIB, entonces los eventos dejan de venir de este archivo
mv newfile file IN_ATTRIB, entonces los eventos dejan de venir de este archivo

En un momento me pareció ver que geditse disparaba también IN_DELETE_SELFantes de quedarme en silencio.

En el caso de que un usuario use vimy gedit, dejo de recibir inotifyeventos una vez que el usuario haya terminado las ediciones. ¿Cómo debo lidiar con esto?

Lo único que veo en común es el IN_ATTRIBevento. Sospecho que cuando reciba el IN_ATTRIBevento, debería hacerlo inotify_rm_watch()y wdluego volver a crear uno nuevo inotify_add_watch()basado en la misma ruta. ¿Pero es ese el enfoque correcto?

Otra opción podría ser observar el directorio principal. El nombre del archivo afectado está incluido en el archivo inotify_event::name, por lo que puedo filtrar el archivo de interés y activar cualquier IN_MODIFYlugar IN_CLOSE_WRITEque namecoincida con mi archivo de interés.

Respuesta1

Como menciona ikkachu, algunos editores crean un nuevo archivo y luego reemplazan el original, cambiando el inodo. Eso significa que cualquier reloj con la descripción de reloj original caducará.

La respuesta es mirar el directorio principal y verificar si hay cambios en cualquier archivo con el nombre de destino. Algo como esto:

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();
}

Estos eventos ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE) capturan las técnicas que probé anteriormente ( touch, echo "" >, vim, nano, gedit). Apuesto a que también podría capturar enlaces simbólicos modificados con estos.

Respuesta2

O podrías usar fatrace, que es mucho más rápido y no tiene tales problemas, por ejemplo, algo como esto:

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

información relacionada