Как узнать, кто использует файл в Linux
В этой статье мы объясним, как узнать, кто использует тот или иной файл в Linux. Это поможет вам узнать системного пользователя или процесс, который использует открытый файл.
Мы можем использовать Linux, все это файл.
Lsof используется в файловой системе, чтобы определить, кто использует какие-либо файлы в этой файловой системе. Вы можете запустить команду lsof в файловой системе Linux, и выходные данные идентифицируют владельца и информацию о процессах, использующих файл, как показано в следующем выводе.
$ lsof /dev/null
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd 1480 tecmint 0r CHR 1,3 0t0 6 /dev/null sh 1501 tecmint 0r CHR 1,3 0t0 6 /dev/null sh 1501 tecmint 1w CHR 1,3 0t0 6 /dev/null dbus-daem 1530 tecmint 0u CHR 1,3 0t0 6 /dev/null xfce4-ses 1603 tecmint 0r CHR 1,3 0t0 6 /dev/null xfce4-ses 1603 tecmint 1w CHR 1,3 0t0 6 /dev/null at-spi-bu 1604 tecmint 0r CHR 1,3 0t0 6 /dev/null dbus-daem 1609 tecmint 0u CHR 1,3 0t0 6 /dev/null at-spi2-r 1611 tecmint 0u CHR 1,3 0t0 6 /dev/null xfconfd 1615 tecmint 0u CHR 1,3 0t0 6 /dev/null xfwm4 1624 tecmint 0r CHR 1,3 0t0 6 /dev/null xfwm4 1624 tecmint 1w CHR 1,3 0t0 6 /dev/null xfce4-pan 1628 tecmint 0r CHR 1,3 0t0 6 /dev/null xfce4-pan 1628 tecmint 1w CHR 1,3 0t0 6 /dev/null Thunar 1630 tecmint 0r CHR 1,3 0t0 6 /dev/null Thunar 1630 tecmint 1w CHR 1,3 0t0 6 /dev/null xfdesktop 1632 tecmint 0r CHR 1,3 0t0 6 /dev/null xfdesktop 1632 tecmint 1w CHR 1,3 0t0 6 /dev/null .
Чтобы вывести список открытых файлов, определенных пользователем, выполните следующую команду, заменив tecmint на фактическое имя пользователя.
$ lsof -u tecmint
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd 1480 tecmint cwd DIR 8,3 4096 2 / systemd 1480 tecmint rtd DIR 8,3 4096 2 / systemd 1480 tecmint txt REG 8,3 1595792 3147496 /lib/systemd/systemd systemd 1480 tecmint mem REG 8,3 1700792 3150525 /lib/x86_64-linux-gnu/libm-2.27.so systemd 1480 tecmint mem REG 8,3 121016 3146329 /lib/x86_64-linux-gnu/libudev.so.1.6.9 systemd 1480 tecmint mem REG 8,3 84032 3150503 /lib/x86_64-linux-gnu/libgpg-error.so.0.22.0 systemd 1480 tecmint mem REG 8,3 43304 3150514 /lib/x86_64-linux-gnu/libjson-c.so.3.0.1 systemd 1480 tecmint mem REG 8,3 34872 2497970 /usr/lib/x86_64-linux-gnu/libargon2.so.0 systemd 1480 tecmint mem REG 8,3 432640 3150484 /lib/x86_64-linux-gnu/libdevmapper.so.1.02.1 systemd 1480 tecmint mem REG 8,3 18680 3150450 /lib/x86_64-linux-gnu/libattr.so.1.1.0 systemd 1480 tecmint mem REG 8,3 18712 3150465 /lib/x86_64-linux-gnu/libcap-ng.so.0.0.0 systemd 1480 tecmint mem REG 8,3 27112 3150489 /lib/x86_64-linux-gnu/libuuid.so.1.3.0 systemd 1480 tecmint mem REG 8,3 14560 3150485 /lib/x86_64-linux-gnu/libdl-2.27.so .
Еще одно важное применение lsof — узнать, какой процесс прослушивает определенный порт. Например, определите процесс, прослушивающий порт 80, с помощью следующей команды.
$ sudo lsof -i TCP:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME httpd 903 root 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1320 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1481 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1482 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1493 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1763 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2027 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2029 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2044 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 3199 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 3201 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN)
Примечание. Поскольку lsof считывает память ядра при поиске открытых файлов, быстрые изменения в памяти ядра могут привести к непредсказуемым результатам. Это один из основных недостатков использования команды lsof.
Дополнительные сведения см. на справочной странице lsof:
$ man lsof
Вот и все! В этой статье мы объяснили, как узнать, кто использует тот или иной файл в Linux. Мы показали, как идентифицировать владельца и обрабатывать информацию для процессов, использующих открытый файл. Используйте форму обратной связи ниже, чтобы связаться с нами по любым вопросам или комментариям.
14. Процессы №1: Информация о процессах №1
Как мы уже выяснили, программы хранятся в файловой системе на накопителе – т.е. жёстком диске или ssd. Когда мы запускаем программу, она загружается в оперативную память, так как скорость чтения с жёсткого диска или даже ssd относительно низкая, а процессор работает на больших скоростях. Как правило, большие программы загружаются в оперативную память не полностью, а по мере необходимости. При этом, для каждой программы создаётся иллюзия, что она – единственная в оперативной памяти, то есть для неё создаётся так называемая «виртуальная память». Также программы при запуске загружают какие-то файлы, будь то файлы настроек или пользовательские файлы – как например, если мы запускаем nano file, то в память загружаются как сам /usr/bin/nano, его настройки — /etc/nanorc и ~/.nanorc, всякие библиотеки, необходимые для работы nano и сам файл, который мы открываем. Кроме этого также запускаемой программе передаются переменные окружения и ещё много всего. Ну и находясь в оперативке, эта программа делает какие-то вычисления с помощью центрального процессора, обрабатывает данные и сохраняет на диске. И совокупность всего этого называется процессом.
Иногда одной программе нужно бывает выполнить несколько операций параллельно. Представьте себе сложное математическое уравнение – есть всякие скобки, умножения и прочее. Такое уравнение можно разделить на составляющие и компьютер может разом выполнить все составляющие, а потом, используя результаты, получить простое уравнение и выполнить его. Или, допустим, веб сервер – к нему обращаются много клиентов, и каждого из них он должен обслужить и желательно параллельно. Для этого один процесс может разделяться на так называемые потоки – все они используют общую виртуальную память. У каждого процесса есть как минимум один поток.

И так, выполняемая программа – это процесс. Начнём с того, что администратору важно видеть список процессов. Для этого есть несколько способов, начнём с утилиты ps. Если просто запустить:
мы увидим список процессов, запущенных в этом терминале. Как вы заметили, вывелось 2 строчки – bash и ps. При том, что ps у нас выполнился за какие-то доли секунды, он у нас всё равно виден в выводе – потому что он делает эдакий скриншот процессов именно в момент выполнения, поэтому и видит сам себя.

Вообще, ps работает с 3 видами ключей: юниксовыми – они обычно начинаются на один дефис (-), BSD-шные – вовсе без дефиса и GNU-шные – как правило это слова, поэтому, чтобы не счесть их за комбинацию букв, используется два дефиса. Если посмотреть документацию:
man ps
можно заметить очень много дублирующихся ключей. Но документация по ps огромная, да и все ключи знать не нужно. Достаточно выучить какую-то одну комбинацию, которая подойдёт в большинстве случаев:
ps -ef
а если вам понадобится что-то конкретное, то всегда можно погуглить или найти в мане.

Как видите, вывод у ps довольно большой и не помещается на экране, поэтому урезается сбоку. Чтобы мы могли нормально прочесть, мы можем передать вывод ps команде less. Правда по умолчанию less переносит текст на новые строки, из-за чего сбиваются столбцы, поэтому less лучше использовать с ключом -S, который не переносит строки. В итоге:
ps -ef | less -S
Давайте разберём, что означают ключи и как читать вывод. Ключ -e выводит все процессы всех пользователей:
ps -e
Да, процессы запускаются от имени пользователей. От этого зависит какие права будут у процесса. Допустим, если я запускаю программу nano от пользователя user, то программа сможет работать с моими файлами. А ключ f:
ps -f
показывает чуть больше информации о процессе. Давайте пройдёмся по столбикам:
ps -ef | less -S

Первое – UID – user id — пользователь, который запустил процесс. Большинство процессов в системе запущены от пользователя root – его также называют суперпользователем – это юзер, у которого есть все права на систему. По возможности, люди стараются не использовать рута везде. Если у программы будет какой-то баг или уязвимость и если она запущена от рута, то программа может сильно навредить системе. Поэтому для программ, которые не требуют особых прав, обычно создают сервисных пользователей. Как правило при установке программы она сама всё это настраивает. Ну и наконец у нас тут есть программы, запущенные от нашего пользователя. Как видите, я вроде ничего кроме эмулятора терминала не запускал, а в системе уже пару сотен процессов.
Второй столбик – PID – process id – идентификатор процесса. Он уникальный для каждого процесса, но совпадает для потоков одного процесса. Когда программа завершается, она освобождает номер и через какое-то время другая программа может использовать этот номер. С помощью этих номеров мы можем управлять процессами.

Третий столбик – PPID – parent process id – идентификатор родительского процесса. Почти все процессы в системе были запущены каким-то другим процессом. Допустим, когда мы запускаем эмулятор терминала, а в нём nano – то родительским процессом для nano является bash, который запущен в этом эмуляторе терминала:
ps -ef | grep nano
Родительским процессом для этого bash:
ps -f ppid
является gnome — процесс рабочего окружения. Родительским процессом для него является systemd — первый процесс. О systemd мы ещё поговорим.

Четвёртый столбик – C – использование процессора данным процессом. Много где у нас нули, но давайте запустим какое-нибудь тяжёлое приложение, допустим, firefox, найдём этот процесс:
ps -ef | grep firefox | less -S
и увидим, что для него это значение отличается от нуля.

Дальше — TTY – от слова телетайп. На хабре есть неплохая статья, объясняющая разницу между телетайпом, консолью, терминалом и т.п. А ps в этом столбике говорит, с каким терминалом ассоциируется данный процесс. Обычно, процесс, запущенный системой и не требующий графики, вывода информации на экран, не связан ни с каким терминалом. Процессы, требующие графики, завязаны на каком-нибудь виртуальном терминале – о них мы говорили ранее. Можно заметить, что тут указано tty1 и tty2 – если нажать правый ctrl + f1 или ctrl+f2, можно увидеть, что именно здесь у нас запущен графический интерфейс. При переходе на ctrl+f3 и далее открывается виртуальный терминал. А для эмуляторов терминала здесь могут быть значения pts/0, pts/1, pts/2 и т.п.

Ещё одно поле – TIME – это сколько времени процессор потратил на работу с данным процессом. Вы можете заметить, что здесь сплошные нули – потому что большинство этих процессов не требуют и секунды процессорного времени. Но если немного поработать с тем же браузером, то это время будет расти:
ps -ef | grep firefox
Кстати, чтобы мне не приходилось постоянно запускать эту команду, я могу использовать команду watсh:
watch "ps -ef | grep firefox"
Эта команда будет каждые 2 секунды запускать указанную команду. И так мы видим, что параметр TIME для нашего браузера постоянно увеличивается.

Ну и последнее – CMD – это команда, которая запустила процесс. Некоторые значения в квадратных скобках – для таких процессов ps не смог найти аргументов – обычно это процессы самого ядра.
Ладно, с выводом ps разобрались. Теперь мы знаем, где найти информацию о процессах. Но, помните, я говорил, что в Unix подобных системах придерживаются идеи «Всё есть файл»? И даже процессы у нас представлены в виде файлов. Но хранить информацию о процессах на жёстком диске нецелесообразно – какие-то процессы существуют доли секунд, какие-то появляются и удаляются сотнями – жёсткий диск не подходит для такого. А вот в оперативной памяти информацию о процессах можно спокойно хранить и представлять в виде файлов. Но раз уж речь идёт о файлах, то нам нужна файловая система. И вот ядро действительно создаёт так называемую виртуальную файловую систему, которая существует только в оперативной памяти.

Вообще, этих виртуальных файловых систем несколько, они используются для разных задач, мы о них поговорим в другой раз. Сейчас нас интересует файловая система procfs. Она примонтирована в директорию /proc:
cd /proc ls
Если посмотреть содержимое этой директории, мы увидим кучу директорий и файлов. Директории вам ничего не напоминают? Именно, это номера процессов, т.е. pid-ы. Ядро операционной системы генерирует эту информацию налету, стоит нам посмотреть – мы увидим актуальную информацию.

В этой директории кроме директорий процессов есть много других файлов – допустим, version:
сat version
показывает нам информацию о версии ядра или uptime:
cat uptime
информацию о том, сколько секунд включена система. Ну в секундах непонятно, поэтому легче использовать утилиту uptime. Кстати, постарайтесь самостоятельно найти, что означает второе значение в файле /proc/uptime и напишите в комментариях так, чтобы было понятно всем.

Ну и давайте посмотрим, что же такого в директориях процессов. Найдём pid процесса, допустим того-же firefox:
ps -ef | grep firefox
и зайдём в эту директорию:
сd pid ls
Тут у нас тоже куча файлов, которые относятся к нашему процессу. Эти файлы нужны не столько для людей, сколько для программ.

Какие-то из этих файлов и мы можем прочесть. Например, cmdline:
cat cmdline
Тут отображена команда, которая запустила процесс. Или environ:
cat environ
те переменные, которые передались процессу при запуске. Или status:
cat status
Какие-то из этих строчек понятны, а какие-то без гугла не разберёшь. Знать всё это не нужно, но, со временем, углубляясь в теорию или сталкиваясь с какими-то проблемами, вы начнёте разбираться в этих файлах.
© Copyright 2021, GNU Linux Pro, CC-BY-SA-4.0. Ревизия 5f665cc2 .
Как узнать, кто использует файл в Linux

В этой статье мы объясним, как узнать, кто использует тот или иной файл в Linux.
Это поможет вам узнать системного пользователя или процесс, который использует открытый файл.
Мы можем использовать команду lsof, чтобы узнать, использует ли кто-то файл, и если да, то кто.
Команда читает память ядра в поиске открытых файлов и помогает вам перечислить все открытые файлы.
В этом случае открытым файлом может быть обычный файл, каталог, специальный файл блока, специальный символьный файл, поток, сетевой файл и многие другие – потому что в Linux все является файлом.
Lsof используется в файловой системе для определения того, кто использует какие-либо файлы в этой файловой системе.
Вы можете запустить команду lsof в файловой системе Linux, и выходные данные идентифицируют владельца и информацию о процессах для процессов, использующих файл, как показано в следующих выходных данных.
$ lsof /dev/null
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME systemd 1480 itisgood 0r CHR 1,3 0t0 6 /dev/null sh 1501 itisgood 0r CHR 1,3 0t0 6 /dev/null sh 1501 itisgood 1w CHR 1,3 0t0 6 /dev/null dbus-daem 1530 itisgood 0u CHR 1,3 0t0 6 /dev/null xfce4-ses 1603 itisgood 0r CHR 1,3 0t0 6 /dev/null xfce4-ses 1603 itisgood 1w CHR 1,3 0t0 6 /dev/null at-spi-bu 1604 itisgood 0r CHR 1,3 0t0 6 /dev/null dbus-daem 1609 itisgood 0u CHR 1,3 0t0 6 /dev/null at-spi2-r 1611 itisgood 0u CHR 1,3 0t0 6 /dev/null xfconfd 1615 itisgood 0u CHR 1,3 0t0 6 /dev/null xfwm4 1624 itisgood 0r CHR 1,3 0t0 6 /dev/null xfwm4 1624 itisgood 1w CHR 1,3 0t0 6 /dev/null xfce4-pan 1628 itisgood 0r CHR 1,3 0t0 6 /dev/null xfce4-pan 1628 itisgood 1w CHR 1,3 0t0 6 /dev/null Thunar 1630 itisgood 0r CHR 1,3 0t0 6 /dev/null Thunar 1630 itisgood 1w CHR 1,3 0t0 6 /dev/null xfdesktop 1632 itisgood 0r CHR 1,3 0t0 6 /dev/null xfdesktop 1632 itisgood 1w CHR 1,3 0t0 6 /dev/null
Еще одно важное использование lsof – выяснение процесса прослушивания определенного порта.
Например, определите процесс, прослушивающий порт 80, с помощью следующей команды.
$ sudo lsof -i TCP:80
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME httpd 903 root 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1320 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1481 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1482 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1493 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 1763 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2027 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2029 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 2044 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 3199 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN) httpd 3201 apache 4u IPv6 20222 0t0 TCP *:http (LISTEN)
Примечание. Поскольку lsof читает память ядра при поиске открытых файлов, быстрые изменения в памяти ядра могут привести к непредсказуемым результатам. Это один из основных недостатков использования команды lsof.
Для получения дополнительной информации, смотрите man-страницу lsof:
$ man lsof
Это все! В этой статье мы объяснили, как узнать, кто использует тот или иной файл в Linux.
Мы показали, как идентифицировать владельца и обрабатывать информацию для процессов, используя открытый файл.
Используйте форму обратной связи ниже, чтобы связаться с нами по любым вопросам или комментариям.
Утилита lsof — инструмент администратора
Во время работы в Linux мне иногда приходилось сталкиваться с одной проблемкой. Установил я, скажем, диск CD-ROM в привод, смонтировал его, потом в процессе работы запустил кучу разных приложений, про CD в приводе уже и забыл. Затем мне потребовалось что-то прочитать с другого диска, я жму на кнопочку извлечения диска на панели CD-ROM, однако реакции никакой не следует. А в ответ на команду
[user]$ umount /mnt/cdrom/
выдается такое сообщение:
umount: /mnt/cdrom: device is busy
Приложений у меня открыто много, так что я уже и не помню, какое из них открыло файлы на CD и тем самым препятствует размонтированию диска. И иногда даже последовательный перебор всех открытых окон не позволял понять, что же надо закрыть. Я помнил, правда, что есть статья С.Лапшанского с описанием решения аналогичной проблемы, да все руки не доходили заняться этим. Но вот надоело мне в конце концов все время наступать на одни и те же грабли, и решил я разобраться с CD-ROM и его размонтированием. Вначале просмотрел я свой каталог на сайте http://rus-linux.net и статью Лапшанского [2] разыскал, но оказалось, что рассматривается в ней аналогичная проблема во FreeBSD, и решается она с помощью утилиты fstat . Я, конечно, попытался вызвать эту команду в своей системе на основе дистрибутива ASP Linux 7.3, но такой команды в моей системе не обнаружилось. Команда man fstat сообщила, что есть такой системный вызов fstat , который выдает информацию об указанном файле, но писать собственную утилиту на основе этого системного вызова мне, прямо признаюсь, не по силам.
Сейчас я даже уже и не вспомню, откуда я это знал, но где-то в глубинах подсознания мелькнула мысль, что для решения этой проблемы можно использовать утилиту lsof . Кстати, один из читателей моей книги [3] в своем отзыве на книгу в качестве недостатка указал на то, что эта утилита в книге не описана. Я и решил попытаться применить lsof для решения своей задачи, и начал, естественно, с изучения справки, выдаваемой командой man lsof . А кроме того, поискал информацию в Интернет и нашел статьи [4-8]. Все эти материалы и послужили основой для настоящей статьи.
Для чего служит команда lsof
Относительно lsof справка man как раз сообщает, что lsof есть сокращение от LiSt of Open Files, и что утилита эта служит для вывода информации о том, какие файлы используются теми или иными процессами. Причем утилита эта имеется в очень многих версиях и диалектах UNIX, включая Linux версии 2.1.72 и выше, а также в HP-UX, AIX, NextStep, Apple Darwin для Power Macintosh, SCO UnixWare, Solaris, FreeBSD, NetBDS, OpenBSD и так далее.
Создателем программа lsof является Victor A. Abell, его домашняя страничка расположена по адресу http://people.freebsd.org/~abe/ , где вы можете найти исходные коды программы. Их можно также скачать с FTP-сайта ftp://vic.cc.purdue.edu/pub/tools/unix/lsof. О том, как скомпилировать и установить программу, вы можете прочитать в статье [8].
Если запустить эту утилиту без параметров, выдается информация о всех работающих процессах и открытых ими файлах. Даже в моей системе с одним пользователем эта команда выдала 2344 строки текста. Попробуй проанализируй эту массу информации! Но давайте взглянем хотя бы на несколько строк ее вывода, чтобы на этом примере понять, какую же информацию она выдает.
Кстати, если вы будете экспериментировать, имейте в виду, что будучи запущенной простым пользователем, эта команда выдает информацию только о процессах, запущенных этим пользователем. Поэтому во многих случаях вы можете не получить от нее никакого ответа. Если вы хотите получить вразумительный ответ на любой свой запрос, ее необходимо запускать от имени root-а (можно воспользоваться следующей формой запуска sudo lsof ). Кроме того, команда отрабатывает достаточно медленно, так что будьте терпеливы и не щелкайте раньше времени + — программа не зависла, просто идет поиск информации.
А теперь смотрим листинг 1 (или результат работы программы на вашем экране).
Листинг 1. Вывод команды lsof.
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME init 1 root cwd DIR 3,3 4096 2 / init 1 root txt REG 3,3 27036 161176 /sbin/init init 1 root mem REG 3,3 103044 160493 /lib/ld-2.3.2.so init 1 root 10u FIFO 3,3 71954 /dev/initctl portmap 1528 rpc 3u IPv4 1656 UDP *:sunrpc xinetd 1649 root 0r CHR 1,3 65970 /dev/null rpc.mount 1682 root 5u unix 0xc34cea80 10311 socket nmbd 1790 root 6u IPv4 2456 UDP *:netbios-ns sh 23252 kos 4u CHR 5,0 70758 /dev/tty sh 23252 kos 6u CHR 136,3 5 /dev/pts/3 sh 23252 kos 8w FIFO 0,5 840800 pipe sh 23253 kos cwd DIR 3,3 4096 160487 /usr/share/man sh 23253 kos rtd DIR 3,3 4096 2 / sh 23253 kos txt REG 3,3 626028 160664 /bin/bash
Как видите, один и тот же процесс открывает много файлов, каждому из которых соответствует строка в выводе lsof . В начале строки указывается имя процесса, его идентификатор, имя пользователя, запустившего процесс. В столбце FD стоит номер файлового дескриптора или одна из следующих буквенных комбинаций (я не берусь корректно перевести на русский язык некоторых из расшифровок этих сокращений, так что привожу их в том виде, как они выдаются справочной системой):
- cwd — текущий рабочий каталог;
- ltx — текст разделяемой библиотеки;
- mxx — hex memory-mapped type number xx.
- m86 — DOS Merge mapped file;
- mem — файл, загруженный в память (memory-mapped file), чаще всего – библиотека,
- mmap — memory-mapped device;
- pd — родительский каталог;
- rtd — корневой каталог;
- txt – текст программы (код и данные);
- v86 — VP/ix mapped file.
- r — файл открыт для чтения;
- w – файл открыт для записи;
- u — файл открыт для чтения и для записи;
- пробел – режим доступа неизвестен и файл не блокирован;
- ‘-’ — режим доступа неизвестен, но на файл установлена блокировка.
Опции команды
Поскольку просматривать вывод команды lsof, запущенной без параметров, достаточно неудобно, можно сократить объем выдаваемых данных, конкретизировав ваш запрос, что достигается за счет использования опций. Опций у этой утилиты довольно много и большинство из них действует по принципу ограничения вывода. Если вы указываете, например, опцию -U, то будут выведены только данные о сокетах UNIX, а все другие файлы игнорируются. Если указать две или более опций, то их действие определяется правилом ИЛИ, то есть выводится информация, определяемая каждой из опций. Например, команда /usr/sbin/lsof -U -u kos выдаст данные о всех открытых UNIX-сокетах и всех файлах, принадлежащих процессам, запущенным пользователем “kos”. Если же необходимо скомбинировать действие опций по принципу логического И, то это делается путем специальной опции -a. Например, команда /usr/sbin/lsof -a -U -u kos выдаст список только сокетов UNIX, принадлежащих процессам, владельцем которых является пользователь “kos”’. Обратите внимание на то, что опция -a стоит не между объединяемыми ею другими опциями. Впрочем, ее можно ставить где угодно, все равно все перечисленные в командной строке опции будут работать по принципу “логическое И”. Но если указывается, например, несколько однотипных опций, то вначале к ним применяется операция логического ИЛИ, а затем уже работает опция -a. Пример: по команде /usr/sbin/lsof -i@aaa.bbb -i@ccc.ddd -a -ufff,ggg будет выведен список файлов, принадлежащих ЛИБО пользователю “fff”, ЛИБО пользователю “ggg” И имеющих сетевые соединения ЛИБО к хосту aaa.bbb ЛИБО к хосту ccc.ddd. Опции команды lsof можно записывать одну за другой без пробелов, предваряя это список всего одним дефисом, то есть вместо /usr/sbin/lsof -a -b -C можно указать просто /usr/sbin/lsof -abC Однако при этом надо побеспокоиться о том, чтобы не было неоднозначности в интерпретации опций. Но я не буду детально рассматривать возможные причины неоднозначности, если у вас возникает желание использовать эту возможность, смотрите соответствующую man-страницу. Отмечу только, что существует ряд опций, которые позволяют изменить вывод программы lsof. Например, опция -R заставляет lsof дополнительно выводить данные об идентификаторе родительского процесса. Очень интересной может оказаться опция -F. Запущенная с этой опцией утилита lsof выдает информацию не в виде таблицы, а в виде последовательности отдельных строк. В таком случае вывод можно перенаправить на вход другой программы, которая будет каким-либо образом обрабатывать полученную информацию. После опции -F можно указать, какие именно поля будут присутствовать в выводе. Например, если командная строка имела вид
[user]$ /usr/sbin/lsof -F pcfn
в выводе lsof будет присутствовать идентификатор процесса (p), имя команды (c), файловый дескриптор (f) и ися файла.
Применение команды lsof
Не имеет смысла повторять в статье описание всех опций этой команды, имеющееся на страничке man. Давайте ограничимся тем, что рассмотрим ее применение и использование наиболее употребительных опций на примерах конкретных ситуаций.
Пример 1. Кто работает с файлом или каталогом?
Начнем с решения той проблемы, которая была описана в начале статьи, и которая рассматривалась в упомянутой выше статье С.Лапшанского [2]. Итак, вы попытались размонтировать CD-ROM (захотели сменить диск). А в ответ получили сообщение “Device is busy”. Это означает, что какой-то процесс открыл файл, расположенный на этом устройстве. А чтобы узнать, какие файлы открыты в том или ином каталоге, служит опция +d команды lsof. Поэтому, чтобы узнать, кем занят диск, дайте команду следующего вида:
[user]$ /usr/sbin/lsof +d /mnt/cdrom
(у меня CD-ROM монтируется в каталог /mnt/cdrom). В ответ я получил такое сообщение:
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME mc 1547 kos cwd DIR 11,0 2048 53248 /mnt/cdrom bash 1556 kos cwd DIR 11,0 2048 53248 /mnt/cdrom
Как видите, сразу становится ясно, что дисковод используется пользователем kos, причем, видимо, какой-то подкаталог каталога /mnt/cdrom открыт в одной из панелей файлового менеджера Mifnight Commander (mc). Надо отметить, что при использовании опции +d dir выдается информация только о тех файлах и подкаталогах, которые содержатся в самом каталоге dir, а не в его подкаталогах. Для решения рассматриваемой проблемы этого вполне достаточно, потому что если обычно в выводе команды указан и файл данного каталога. Но, если вы все же захотите получить список всех открытых файлов во всех вложенных подкаталогах каталога dir, надо воспользоваться опцией +D. Попробуем, например, посмотреть, какие файлы открыты в каталоге /var/ и всех его подкаталогах. В работающей системе всегда найдутся открытые файлы из этого каталога, поэтому на этом примере очень наглядно демонстрируется разница между опциями +d и +D:
[root]# /usr/sbin/lsof +D /var/
(Упомяну для точности, что символические ссылки игнорируются и поэтому в выводе этой команды не перечисляются.) Если вы почему либо хотите указать не имя каталога или файла, а номер файлового дескриптора, вы можете воспользоваться командой lsof -f fd, где fd есть список файловых дескрипторов, разделенных запятыми. В списке можно использовать диапазоны: 1-3,5 и те буквенные сочетания, которые были упомянуты выше, например, cwd,ltx,mem. Между прочим, когда я экспериментировал с командой lsof , выяснилось, что файловый менеджер Konqueror не “держит” устройство: несмотря на то, что в Konqueror открыт каталог, расположенный на примонтированном CD, операция размонтирования устройства выполняется без проблем. По-видимому, Konqueror (как, вероятно, и другие браузеры) скачивает файл и закрывает соединение (файл).
Пример 2. Какой процесс использует данный файл?
[root]# /usr/sbin/lsof /etc/passwd
Приведенный пример очень похож на предыдущий, только вы получаете сведения о процессах, использующих конкретный файл.
Пример 3. Какие ресурсы использует процесс?
Вы уже видели в листинге 1, что каждый процесс открывает несколько файлов. Но когда я выполнил команду
[root]# /usr/sbin/lsof -c mc
я был поражен тем, как много файлов открыто этим процессом. Впрочем, я привел этот пример не для того, чтобы сообщить о своем удивлении. Это пример просто иллюстрирует применение опции — с string в команде lsof. Запущенная с этой опцией lsof выводит список файлов, отрытых процессами, выполняющими команды, название которых начинается строкой string (один или несколько символов). Но строка string может соответствовать нескольким запущенным в данный момент командам. Если вы хотите конкретизировать ваш запрос, вы можете воспользоваться другой опцией: -p pid. Например:
[root]# /usr/sbin/lsof -p 409
Команда lsof -p pid выводит список файлов, открытых процессами, чьи идентификаторы (PID) находятся в списке pid, например, “3593” или “823,451” (отдельные идентификаторы разделяются запятыми, пробелы в списке недопустимы). С помощью этой команды вы сможете увидеть, например, какие библиотеки используются процессом. Номер нужного PID можно извлечь из результатов выполнения команды /usr/sbin/lsof -c string. Аналогичным образом можно вывести список файлов, открытых процессами, чьи идентификаторы группы (PGID) находятся в разделенном запятыми списке gid. Это позволяет сделать команда lsof -g gid .
Пример 4. С какими файлами работает пользователь?
Следующий вариант запуска той же команды:
[root]# /usr/sbin/lsof -u names
позволяет вывести список файлов, открытых всеми процессами, запущенными пользователями, чье имя или идентификатор содержится в списке names. Отдельные элементы списка разделяются запятыми, например, ”548,root” (пробелов быть не должно).
Пример 5. Кто подключился к вашему компьютеру?
Команда lsof очень полезна в том случае, когда вы хотите обеспечить безопасность работы вашего компьютера в сети. С ее помощью вы можете определить, какие порты открыты для приема входящих соединений и какая программа прослушивает каждый порт. После это можно закрыть ненужные порты, чтобы минимизировать риск проникновения в систему злоумышленника. Для того, чтобы узнать, какие процессы в данный момент прослушивают сетевые соединения, воспользуйтесь командой lsof с опцией -i :
[root]# /usr/sbin/lsof -i
На листинге 2 показан результат выполнения этой команды на компьютере trend в моей домашней сети, состоящей всего из двух компьютеров.
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME portmap 557 root 3u IPv4 969 UDP *:sunrpc portmap 557 root 4u IPv4 972 TCP *:sunrpc (LISTEN) rpc.statd 585 root 4u IPv4 1029 UDP *:32768 rpc.statd 585 root 6u IPv4 1032 TCP *:32768 (LISTEN) sshd 727 root 3u IPv4 1176 TCP *:ssh (LISTEN) lpd 783 root 6u IPv4 1258 TCP *:printer (LISTEN) rpc.rquot 813 root 3u IPv4 1303 UDP *:990 rpc.rquot 813 root 4u IPv4 1308 TCP *:imaps (LISTEN) rpc.mount 818 root 3u IPv4 1321 UDP *:32769 rpc.mount 818 root 4u IPv4 1324 TCP *:32769 (LISTEN) httpd 873 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 877 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 881 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 893 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 894 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 895 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 896 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 897 root 16u IPv4 1422 TCP *:http (LISTEN) httpd 898 root 16u IPv4 1422 TCP *:http (LISTEN) smbd 1300 root 9u IPv4 1839 TCP *:netbios-ssn (LISTEN) nmbd 1305 root 6u IPv4 1842 UDP *:netbios-ns nmbd 1305 root 7u IPv4 1843 UDP *:netbios-dgm nmbd 1305 root 8u IPv4 1845 UDP trend.home.kos:netbios-ns nmbd 1305 root 9u IPv4 1846 UDP trend.home.kos:netbios-dgm X 1413 root 1u IPv4 1972 TCP *:x11 (LISTEN) httpd 2190 root 16u IPv4 1422 TCP *:http (LISTEN) sshd 2192 root 4u IPv4 35684 TCP trend.home.kos:ssh->old-lin.home.kos:1031 (ESTABLISHED) sshd 2192 root 8u IPv4 35704 TCP localhost.localdomain:x11-ssh-offset (LISTEN) ssh 2464 root 3u IPv4 71018 TCP trend.home.kos:32772->old-lin.home.kos:ssh (ESTABLISHED)
Порты, которые открыты для входящих соединений, обозначены меткой LISTEN. Метка ESTABLISHED показывает, что по данному порту соединение установлено. В листинге 2 вы можете видеть пример двух SSH-сессий. Первая сессия установлена хостом old-lin.home.kos с компьютером trend.home.kos. Она обслуживается процессом с PID 2192, который был порожден основным демоном sshd, PID 727. Процесс с PID 2464, наоборот, соответствует соединению, установленному клиентской программой ssh на компьютере trend. Поскольку и в этом случае количество информации, выдаваемой командой lsof с опцией -i может оказаться очень велико, можно конкретизировать запрос. Для этого нужно использовать команду в следующем формате:
[root]# /usr/sbin/lsof -i adress
где после опции -i указывается еще параметр – интересующий вас порт, сервис или имя хоста. В общем случае параметр adress задается в следующем виде (квадратные скобки обозначают необязательность каждой части параметра): [46][protocol][@hostname|hostaddr][:service|port] Здесь “46” обозначает версию протокола IP. Цифру 6 можно указывать только в том случае, если ваше ядро поддерживает IPv6. Если не указано ни 4, ни 6, будут рассматриваться соединения по тому и другому варианту протокола. Задавать версию протокола можно указывая опцию в форме -i4 -i6 (это то же самое, что и указать просто -i). Если указывается только версия IP-протокола без указания других частей параметра address, отображаются только данные о тех процессах и файлах, которые работают по соответствующему протоколу. Вместо “protocol” в параметре может стоять либо TCP, либо UDP (либо ничего). “hostname” — имя хоста, а “hostaddr” — числовой адрес. В случае протокола IPv4 эта часть задается в форме десятично-точечной записи, в случае IPv6 – в форме чисел, разделенных двоеточиями и заключенных в скобки. “service” — это название одного из сервисов, например, smtp, или список таких сервисов. “port” — это номер порта или список таких номеров. Чтобы сказанное стало понятнее, приведем несколько простых примеров.
| [root]# lsof -i :80 |
В этом случае будет выдан список всех процессов, прослушивающих или установивших соединение через порт 80.
| [root]# lsof -i :smtp |
В этом примере будут перечислены все соединения, ассоциированные с почтовым протоколом SMTP.
| [root]# lsof -i @rus-linux.net |
В третьем случае будет выдан список всех входящих и исходящих соединений с хостом rus-linux.net.
| [root]# lsof -i UDP@rus-linux.net:123 |
Эта команда покажет, какие процессы установили UDP-соединения с хостом rus-linux.net через порт 123 (ntp). Очевидно, что указание параметра adress полезно только в том случае, когда вы заранее знаете, что именно вам нужно искать. Вы можете таким образом проверить, например, что какой-то конкретный сервис фактически работает и какой порт он прослушивает. Вы можете увидеть, подключился ли кто-то извне к вашему компьютеру по таким протоколам как SSH, Telnet, FTP или другим возможным способом.
Пример 6. Кто открыл файлы по NFS?
Если вы хотите узнать, открыты ли какие-то файлы, предоставленные удаленным пользователям по протоколу NFS, используйте опцию -N.
Пример 7. Наблюдаем за процессом копирования
Предположим, что вы решили переместить из одного каталога в другой большое количество файлов (или большой каталог целиком). И вы хотите видеть, какой именно файл перемещается в данный момент. Тут вам и может помочь утилита lsof. Для этого достаточно дать команду примерно такого вида (в этом примере предполагается, что перемещаются куда-то файлы из каталога Photo):
[user]$ /usr/sbin/lsof | grep Photo
При этом нужно иметь в виду, что команда lsof делает как-бы “мгновенный снимок”, отображающий только лишь состояние процессов и соответствующих файлов в момент ее выполнения. Так что для “наблюдения за процессом” надо повторять ее запуск многократно. И в таком случае может оказаться полезной опция +r, которая служит для периодического повторения запуска команды через заданный промежуток времени.
Заключение
В конце статьи можно сформулировать следующий вывод: поскольку файл и процесс – два ключевых понятия в операционной системе, утилита lsof может оказаться незаменимым помощником администратора в тех случаях, когда надо разобраться, как работает система, а особенно в тех случаях, когда система скомпрометирована. И она тем полезнее, чем больше ваша система и чем больше вы с ней работаете, чем лучше вы понимаете, что она может. Когда вы освоите ее возможности, вы сможете создать отдельные скрипты для обработки тех огромных массивов информации, которые выдает эта программа. Можно, например, запускать команду lsof -i через определенные промежутки времени, чтобы сравнивать полученные данные. Если будут выявлены отличия в числе открытых процессов или другие отличия, удовлетворяющие заданному критерию, скрипт может сформировать сообщение администратору. Мы рассмотрели только малую часть возможностей этой утилиты. Более подробную информацию ищите на соответствующей man-страничке. Можно еще отметить, что для lsof разработана графическая оболочка, называемая GLSOF. Ее можно получить с сайта http://glsof.sourceforge.net/.
Ссылки:
- http://rus-linux.net
- С.Лапшанский, “Кто использует эти файлы”, перевод статьи Майкла Лукаса (URL: http://www.computerra.ru/softerra/freeos/22483/x ).
- В.А.Костромин, “Linux для пользователя”, БХВ-Петербург, 2002 г.
- “Meet the Amazing Mr. Lsof” (URL: http://www.netadmintools.com/art176.html )
- Indiana University, Unix Workstation Support Group, «Unix for Advanced Users”. 15.9. List Open Files: lsof and fuser (URL: http://www.uwsg.iu.edu/UAU/uau.html).
- Thomas Nooning, “Track network connections with LSOF on Linux” (URL: http://www.builderau.com.au/program/unix/0,39024638,20268166,00.htm .
- Martin Zahn, “Introduction to lsof”, (URL: http://www.akadia.com/services/lsof_intro.html ).
- “Installing, configuring and using lsof 4.50 to list open files on systems running Solaris 2.x” (URL: http://www.cert.org/security-improvement/implementations/i042.05.html )