Лучший способ наблюдать за процессом (и подпроцессами) для файловой системы read() I/O?

Я хотел бы разработать программу командной строки, которая работала бы так:

моя программа /c [some_executable_here]

Который запустил команду, указанную пользователем, и «наблюдал» за процессом (и любыми подпроцессами) для чтения ввода-вывода, а когда эта программа выходит, распечатывал список файлов, которые были «прочитаны» (в конечном итоге это привело к read() системный вызов).

Моя начальная ОС для реализации — Windows, но я хотел бы сделать то же самое и в Linux.

Все API-интерфейсы FileSystem, похожие на часы, которые я видел до сих пор, ориентированы на просмотр каталогов (или отдельных файлов), а не на процессы, поэтому я не уверен, как лучше всего это сделать.

EDIT: я ищу примеры кода того, как в конечном итоге реализовать это (или, по крайней мере, указатели на API, которым я мог бы следовать), чтобы сделать это в Windows и Linux.

Также, чтобы было ясно, он не может использовать такой метод, как OpendFilesView, procmon или строки grepping из какого-либо инструмента системного уровня, который не может окончательно идентифицировать процесс по идентификатору (и любые подпроцессы) с начала и конца его выполнения. ; IOW не может быть никаких проблем со временем и возможности ложного срабатывания при поиске «foo.exe» и получении неправильного результата.


person Garen    schedule 17.09.2009    source источник
comment
Я удалил свой ответ, так как iotop полезен только для учета. Он не может знать, какие файлы были изменены (поскольку он использует функцию учета ввода-вывода ядра, а учет предназначен для учета), поэтому он бесполезен для вас. гл :)   -  person Tarnay Kálmán    schedule 29.09.2009


Ответы (3)


В Linux я бы определенно использовал strace — это просто и мощно. Например.:

$ strace -o/tmp/blah -f -eopen,read bash -c "cat ciao.txt"

запускает запрошенную команду (включая подпроцессы, которые она порождает из-за -f), а также оставляет в /tmp/blah (120 строк в моем случае для этого примера), подробно описывая все вызовы открытия и чтения, сделанные этими процессами, и их результаты.

После этого вам потребуется небольшая обработка, чтобы извлечь только тот набор файлов, которые были успешно прочитаны, как вам нужно; например, с Python вы можете сделать:

import re

linere = re.compile(r'^(\d+)\s+(\w+)\(([^)]+)\)\s+\=\s*(.*)$')

def main():
  openfiles = dict()
  filesread = set()
  with open('/tmp/blah') as f:
    for line in f:
      mo = linere.match(line)
      if mo is None:
        print "Unmatched line %r" % line
      pid, command, args, results = mo.groups()
      if command == 'open':
        fn = args.split(',', 1)[0].strip('"')
        fd = results.split(' ', 1)[0]
        openfiles[fd] = fn
      elif command == 'read':
        if results != '0':
          fd = args.split(',', 1)[0]
          filesread.add(openfiles[fd])
      else:
        print "Unknown command %r" % command
  print sorted(filesread)

Это немного упрощено (вам нужно посмотреть некоторые другие системные вызовы, такие как dup &c), но, я надеюсь, показывает суть необходимой работы. В моем примере это выдает:

['/lib/libc.so.6', '/lib/libdl.so.2', '/lib/libncurses.so.5',
 '/proc/meminfo', '/proc/sys/kernel/ngroups_max',
 '/usr/share/locale/locale.alias', 'ciao.txt']

поэтому он также считается «чтением» тех, которые выполняются для получения динамических библиотек и т. Д., А не только «файлов данных» ... на уровне системного вызова разница невелика. Я полагаю, вы могли бы отфильтровать файлы без данных, если вам это нужно.

Я нахожу strace настолько удобным для таких целей, что, если бы мне поручили выполнить ту же работу в Windows, моей первой попыткой было бы перейти на StraceNT -- не на 100 % совместимы, и, конечно, базовые имена системных вызовов и c различаются, но я думаю, что могу объяснить эти различия в своем коде Python (подготовка и выполнение команды strace и постобработка результатов).

К сожалению, некоторые другие системы Unix, насколько мне известно, предлагают такие возможности только в том случае, если вы являетесь пользователем root (суперпользователь) - например. в Mac OS X нужно пройти через sudo, чтобы запустить такие утилиты трассировки, как dtrace и dtruss; Я не знаю прямого переноса strace на Mac или других способов выполнения таких задач без привилегий root.

person Alex Martelli    schedule 27.09.2009

Попробуйте "монитор процессов" (procmon.exe). Это позволяет указать фильтр (имя процесса для просмотра). Затем он перечислит все файлы и операции с указанными файлами.

В Linux попробуйте lsof для текущего снимка и strace для непрерывного мониторинга. Вам придется фильтровать вывод с помощью grep.

Все эти инструменты проверяют структуру процесса (то есть структуру данных, которую ОС использует для управления процессом) и перечисляют упомянутые там дескрипторы/файловые дескрипторы. Это не функция API файловой системы, а API управления процессами.

[EDIT] Чтобы начать работу, см. раздел «Как это работает» на этой странице. написать свой собственный инструмент для Windows.

person Aaron Digulla    schedule 17.09.2009
comment
Я знаю о procmon, но он работает только в течение определенного периода времени, кроме того, я хочу выяснить, как реализовать это с помощью моего собственного кода. - person Garen; 17.09.2009
comment
В OpenedFilesView v1.45 есть объяснение, как это сделать в Windows (см. мои правки) - person Aaron Digulla; 18.09.2009
comment
На веб-странице упоминается, что он использует API-интерфейс NtQuerySystemInformation и имеет драйвер ядра (NirSoftOpenedFilesDriver.sys), но не имеет никакой другой информации о том, как это сделать программно. Это хорошая подсказка для Windows, но недостаточная для того, чтобы я начал как разработчик, никогда не занимавшийся драйверами ядра Windows. - person Garen; 25.09.2009
comment
Спросить у автора и переиспользовать существующий драйвер? - person Aaron Digulla; 25.09.2009
comment
Отправил. Надеюсь, он ответит. :) - person Garen; 01.10.2009

Добавлена ​​опция -d (--watchfd) в 2014 году в pv, чтобы внимательно следить за pid.

Легко запомнить и полезно для отладки.

pv --help
  -d, --watchfd PID[:FD]   watch file FD opened by process PID

Например, чтобы посмотреть процесс по его имени.

pv -d `pgrep firefox`
person NVRM    schedule 12.01.2018