На этот вопрос нет простого ответа, у вас есть следующие вещи:
Inotify
Вы можете использовать inotify
чтобы получать уведомления всякий раз, когда что-то меняет файл. inotify
сам по себе не является утилитой, это интерфейс, предоставляемый ядром Linux, но есть такие утилиты, как, например, inotifywait
из пакета inotify-tools
.
Проблема с inotify
заключается в том, что он не сообщает вам, какой процесс изменил файл.
Пример:
mst@mst-nb1:~$ inotifywait 123
Setting up watches.
Watches established. # now i write to "123" in another terminal
123 MODIFY
lsof
Одна действительно замечательная утилита для определения того, какой процесс держит файл открытым, - это lsof
. Например, выполнив lsof / var / log / syslog
, вы можете увидеть, какие процессы в настоящее время держат этот файл открытым.
Проблема с lsof
заключается в том, что он не может отслеживать этот файл в течение определенного промежутка времени, он может только дать вам моментальный снимок ситуации в тот момент, когда вы его запустите. В вашем случае вы хотите знать, что записывается в этот файл, но вы не знаете наверняка, постоянно ли этот файл открыт (скорее всего, это не так). Если в процессе записи файл не всегда остается открытым, то lsof
вам не сильно поможет, потому что он может указать вам на нужный процесс, только если вы запустите его точно в тот момент, когда он пишет. .
Причина, по которой lsof
не может отслеживать файл так же, как inotify
, заключается в том, что он получает информацию, просто просматривая / proc
файловая система, но не устанавливает никаких наблюдателей.
Пример:
# Terminal 1 (I open the file)
mst@mst-nb1:~$ cat > 123
# Terminal 2
mst@mst-nb1:~$ lsof 123
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
cat 24097 mst 1w REG 252,1 0 16791997 123
loggedfs
Это может быть вашим лучшим шансом, но для его работы требуются некоторые усилия. Вы можете использовать fuse loggedfs
и смонтировать его в каталог, где находится ваш файл журнала. Затем он должен предоставить вам подробную информацию о том, что и когда открывает файл.
Единственная проблема с loggedfs
заключается в том, что им не так просто пользоваться, как какой-нибудь простой утилитой командной строки.
Если вы хотите разобраться с loggedfs
, вы можете обратиться к документации
Заключение
Вывод: у вас есть разные возможности, но нет простой
способ.
Современные оболочки имеют тенденцию восстанавливать терминальное состояние после выхода из программы; Как вы заметили, более старые или менее способные оболочки могут не работать. Обычный подход, который можно увидеть в APUE и других текстах, состоит в том, чтобы сохранить копию состояния терминала, используя tcgetattr
, а затем восстановить это состояние при выходе из программы :
#include <sys/time.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#include <readline/readline.h>
#include <readline/history.h>
struct itimerval Alarm_Timer;
struct termios Original_Termios;
int Need_Reset;
void sigalrm_handler(int arg)
{
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
int main(void)
{
char *line;
tcgetattr(STDIN_FILENO, &Original_Termios);
Need_Reset = 1;
signal(SIGALRM, sigalrm_handler);
Alarm_Timer.it_value.tv_sec = 3;
setitimer(ITIMER_REAL, &Alarm_Timer, NULL);
line = readline("* ");
if (Need_Reset)
tcsetattr(STDIN_FILENO, TCSANOW, &Original_Termios);
exit(0);
}
Во-первых, libreadline
устанавливает свои собственные обработчики сигналов для ALRM
, INT
и т. д. и завершится нормально (после восстановления настроек termios/stty )при получении такого сигнала.
Вы можете проверить, запустив/отследив простую программу, подобную этой:
#include <readline/readline.h>
#include <unistd.h>
int main(void){
alarm(3); readline("foo> ");
}
Таким образом, вы можете просто избавиться от своего обработчика сигнала.
Во-вторых, вы никогда не должны вызывать exit(3)
из обработчика сигнала. exit(3)
, в отличие от системного вызова _exit(2)
, не является безопасным для сигналов, главным образом потому, что он должен запускать обработчики, зарегистрированные с помощью atexit(3)
. Например, просто подумайте, что произойдет, если exit(3)
вызывается, когда другой exit(3)
уже проходит через эти обработчики.
Если вместо использования readline(3)
вы используете свой собственный код, который переводит терминал в необработанный режим и т. д., вы всегда должны сохранять состояние терминала при запуске и при получении SIGCONT
и восстановить его перед выходом из и при получении сигнала SIGTSTP
. Не только при запуске/выходе, как видно во многих примерах. И если вы используете адресацию курсора, вы также должны включать/выключать ca_mode
с экранами smcup
/ rmcup
при сохранении/восстановлении настроек termios.