Файловые дескрипторы Linux

Основными операциями, предоставляемыми ядром операционной системы программам (а точнее — процессам) для работы с файлами, являются системные вызовы open read, write и close. В соответствии со своими именами, эти системные вызовы предназначены для открытия и закрытия файла, для чтения из файла и записи в файл. Дополнительный системный вызов ioctl (input output control) используется для управления драйверами устройств и, как следствие, применяется в основном для специальных файлов устройств.

При запросе процесса на открытие файла системным вызовом оpen производится его однократный (относительно медленный) поиск имени файла в дереве каталогов и для запросившего процесса создается так называемый файловый дескриптор (описатель, от англ, descriptor).

Файловый дескриптор «содержит» информацию, описывающую файл, например индексный дескриптор inode файла на файловой системе, номера major и minor устройства, на котором располагается файловая система файла, режим открытия файла, и прочую служебную информацию.

При последующих операциях read и write доступ к самим данным файла происходит с использованием файлового дескриптора (что исключает медленный поиск файла в дереве каталогов).

Файловые дескрипторы пронумерованы и содержатся в таблице открытых процессом файлов, которую можно получить при помощи диагностической программы lsof.

В обратную сторону получить список процессов, открывших тот или иной файл, можно при помощи программ lsof и fuser, что бывает полезно для идентификации программ, «занявших» файловую систему, подлежащую отмонтированию.

Таблица файловых дескрипторов

john@ubuntu:~$ lsof -р $$

COMMAND     PID    USER     FD     TYPE    DEVICE  SIZE/OFF         NODE    NAME

. . .                                      . . .                                   . . .
bash               17975      john       1u      CHR            136,2              0t0                  5 /dev/pts/2

. . .                                      . . .                                   . . .

2) root@ubuntu:~# lsof /dev/log

COMMAND     PID    USER     FD     TYPE    DEVICE  SIZE/OFF         NODE    NAME

rsyslogd             543     syslog     0u      unix     0xefef5680         0t0            1338 /dev/log

root@ubuntu:~# fuser /dev/log

/dev/log:                                  543
root@ubuntu:~# ps p 543

PID  TTY                STAT     TIME   COMMAND
543   ?                        Sl            0:43        rsyslogd -c5

root@ubuntu:~# lsof /var/log/syslog

COMMAND     PID    USER     FD     TYPE    DEVICE  SIZE/OFF         NODE    NAME

rsyslogd              543    syslog     lw      REG        252,0             29039   26214496 /var/log/syslog

В первом примере из листинга выше показано получение списка файловых дескрипторов (столбец FD) процесса командного интерпретатора bash пользователя john, на котором файловый дескриптор номер 1 описывает открытый на чтение и запись и специальный символьный CHR файл устройства /dev/pts/2.

Во втором примере показано получение информации о процессе, открывшем файловый сокет unix с именем /dev/log (файловый дескриптор номер 0 на чтение и запись u) и обычный файл REG с именем /var/log/sysog (файловый дескриптор номер 1 на запись w).

Пронаблюдать за использованием системных вызовов файлового программного интерфейса в момент выполнения программам позволяет системный трассировщик strace.

Трассировка файлового программного интерфейса

john@ubuntu:~$ date

Вт. окт. 15 18:17:42 MSK % 2018

john@ubuntu:~$ strace -fe open, close, read, write, ioctl date

. . .                           . . .                           . . .

open(«/etc/localtime», 0_RDONLY|0_CLOEXEC) = 3

. . .                           . . .                          . . .

john@ubuntu:~$ file /etc/localtime
/etc/localtime: timezone data, version 2, 13 gmt time flags, 13 std time flags, no leap

seconds, 77 transition tines, 13 abbreviation char
john@ubuntu:~$ ls -la /dev/dvd
lrwxrwxrwx  1  root  root  3  окт. 16 18:09 /dev/dvd -> sr0

john@ubuntu:~$ strace -fe open,close, read,write,ioctl eject

. . .                           . . .                          . . .
open(«/dev/sr0», O_RDWR|O_N0NBLOCK)   = 3
ioctl(3, CDROMEJECT, 0x804cb4e)                   = 0
closed(3)                                                                     = 0
john@ubuntu: ~$ strace -fe open, read,write,close,ioctl setleds -L +num +scroll
ioctl(0, KDGKBLED, 0xbfe4f4ff) = 0
ioctl(0, KDGETLED, 0xbfe4f4fe) = 0
ioctl(0, KDSETLED, 0x3)             = 0

Предположив, что программа date показывает правильное московское время, потому что узнаёт заданную временную зону MSK из некоего конфигурационного файла операционной системы, при трассировке ее «работы можно установить его точное имя — /etc/localtime.

Аналогично предположив, что программа eject открывает лоток привода CD/DVD при помощи специального файла устройства, при трассировке можно узнать имя файла /dev/sr0, номер файлового дескриптора при работе с файлом 3 и команду CDROMEJECT соответствующего устройству
драйвера ioctl_List.

Трассировка команды setleds показывает, что она вообще не открывает никаких файлов, но пользуется файловым дескриптором о так называемого стандартного потока ввода (прикрепленного, к текущему терминалу) и командами kdgetled и kdsetled драйвера консоли console_ioctl.

 

Добавить комментарий