Подключенные устройства Linux
Работа с устройствами в Linux очень сильно отличается от Windows. Главная концепция Linux в том, что все есть файл, не только пользовательские файлы с информацией, но и различные настройки ядра, подключенные устройства, память, сетевые соединения, все это представлено в виде файлов, которые размещены в специальных файловых системах.
С помощью этих файлов система работает с устройствами, и вы можете ими управлять с помощью различных утилит. В этой статье мы рассмотрим как выполняется работа с устройствами Linux, что из себя представляют устройства Linux, а также рассмотрим несколько примеров создания файлов устройств и обращения к ним. Это довольно интересная тема.
Файлы устройств Linux
Все файлы устройств расположены в каталоге /dev, который есть неотделимой частью корневой файловой системы, поскольку они должны быть доступны на всех этапах загрузки. Они также известны как специальные файлы устройств. Эти файлы используются операционной системой для обеспечения пользователю и программам интерфейса доступа к устройствам, подключенным к компьютеру.
Самое важное, что нужно знать об этих файлах — это не драйверы устройств, их лучше рассматривать как интерфейс доступа к драйверам устройств. Приложение отправляет данные в файл устройства, откуда они читаются драйвером устройства и отправляются на физическое устройства. Обратная передача от физических устройств тоже проходит по этому пути через файл устройства. Давайте посмотрим как будет выглядеть поток передачи данных для типичной команды, например, cat:
На схеме приведена схема передачи данных для команды cat /etc/resolv.conf. Вы выполняете команду из терминала, утилита отправляет запрос файла драйверу, который ищет файл на диске и читает его содержимое. Данные передаются через файл устройства, а затем опять же, через файл устройства псевдо-терминала передаются в эмулятор терминала 6, где они будут отображены.
Если мы перенаправим вывод команды в файл, например, cat /etc/resolv.conf > /etc/resolv.bak, то левая часть схемы останется неизменной, а правая сторона будет вести к файлу устройства /dev/sda2. Эти устройства делают очень простым использование стандартных потоков ввода/вывода для доступа к каждому устройству. Простое перенаправление потока данных в файл устройства приведет к записи данных на устройство.
Классификация файлов устройств
Файлы устройств можно классифицировать по меньшей мере двумя способами. Первая и наиболее широкая классификация — на основе потока данных. В устройствах TTY и других символьных устройствах, данные обрабатываются по одному символу или байту за раз. В блочных устройствах, таких как жесткие диски данные передаются блоками, как правило, с размером, кратным 256 байт.
Если вы еще этого не делали, то перейдите в папку /dev/ и посмотрите список находящихся там файлов с помощью команды ls. Вы увидите очень длинный список файлов с их правами доступа, владельцами и группами — это список устройств linux. Обратите внимание на самый первый символ в каждой строке. Он указывает тип устройства. Символом «b» — обозначаются блочные устройства linux (block), а символом «c» — символьные (character).
Более точно можно идентифицировать устройства по их младшему и старшему номеру. Например, жесткие диски имеют старший номер 8, что обозначает их как блочные устройства SCSI. Обратите внимание, что все жесткие диски PATA и SATA находятся под управлением SCSI. Раньше использовалась подсистема ATA, но она уже устарела, поэтому диски, которые раньше обозначались как hd[a-z] теперь обозначаются sd[a-z].
Младший номер диска означает раздел устройства, например, номера 8/0 — это весь диск /dev/sda, а 8/1 уже файл первого раздела на диске, 8/6 — /dev/sda6. Файлы TTY именуются немного по-другому, от tty0 до tty63. Все значения старших номеров устройств Linux вы можете найти на официальном сайте ядра.
Работа с устройствами в Linux
Давайте проведем несколько экспериментов, которые помогут вам понять как работают устройства Linux и как ими управлять в этой операционной системе. Большинство дистрибутивов Linux имеют несколько виртуальных консолей, обычно от 1 до 7, которые могут использоваться для входа в сеанс командной оболочки. К этим виртуальным консолям можно получить доступ с помощью сочетаний клавиш Ctrl+Alt+Fn, например, Ctrl+Alt+F1 для первой консоли, Ctrl+Alt+F2 для второй и так далее.
Сейчас нажмите Ctrl+Alt+F2 для перехода во вторую консоль, в некоторых дистрибутивах, кроме запроса логина и пароля, будет выведена информация про активную TTY связанную с этой консолью. Но этой информации может и не быть. В данном случае консоль будет связана с устройством tty2.
Войдите от имени обычного пользователя, затем наберите такую команду, чтобы посмотреть номер устройства tty:
У меня вы видите устройство /dev/pts/0, это виртуальное устройство эмулятора терминала, но если вы будете выполнять задачу в tty2, то отобразиться именно она. Теперь давайте посмотрим список tty устройств с помощью команды ls:
Нас будут интересовать не все устройства, а только первые три. В этих устройствах нет ничего особенного, это обычные устройства символьного типа. Устройство tty2 подключено к консоли 2, устройство tty3 подключено к консоли 3.
Нажмите сочетание клавиш Ctrl+Alt+F3, чтобы переключиться в третью консоль, затем выполните команду:
echo «Hello world» > /dev/tty2
Затем вернитесь во вторую консоль. Здесь вы увидите отправленную строку, Hello World. Все это можно повторить с помощью эмуляторов терминала в графическом интерфейсе, только здесь будут использоваться псевдо-терминальные устройства /dev/pts/*. Теперь попробуем отобразить содержимое файла fstab с помощью cat в другом терминале:
cat /etc/fstab > /dev/tty2
С помощью cat вы можете отправить файл непосредственно на принтер. Например, если устройство принтера /dev/usb/lp0, то для печати файла будет достаточно выполнить:
cat test.pdf > /dev/usb/lp0
Каталог /dev/ содержит много интересных файлов устройств. Это интерфейсы доступа к аппаратному обеспечению и вам не нужно думать, что это, жесткий диск или экран. Например, вся оперативная память компьютера доступна в виде устройства /dev/mem. С помощью него вы можете иметь прямой доступ к памяти. Мы можем вывести содержимое памяти в терминал:
dd if=/dev/mem bs=2048 count=100
Утилита dd, в отличие от cat дает больше контроля над процессом и позволяет указать сколько данных нужно прочитать. Но не ко всей памяти вы можете получить доступ. В ядре встроена защита, поэтому обычно, вы можете читать память, только для своего процесса.
Также тут есть файлы, которые несвязанны ни с какими реальными устройствами, это null, zero, random и urandom. Устройство /dev/null может использоваться для перенаправления вывода команд, чтобы данные никуда не выводились. Устройство /dev/zero используется для получения строки, заполненной нулями.
Вы можете использовать ту же команду dd, чтобы попытаться вывести ряд символов с устройства /dev/null:
dd if=/dev/null bs=512 count=500 | od -c
Обратите внимание, что ничего выведено не будет, потому что это устройство пусто, оно только принимает данные и никуда их не сохраняет.
Устройства /dev/random и /dev/urandom позволяют получить случайные комбинации чисел или байт. Вы можете использовать такую команду, чтобы получить случайные байты информации:
Для остановки нажмите Ctrl+C. Устройство urandom позволяет генерировать случайные последовательности независимые от предыдущего числа, в качестве источника энтропии используется нажатия клавиш и движения мыши.
Устройство /dev/zero позволяет получить строку, заполненную нулями. Для проверки используйте такую команду:
dd if=/dev/zero bs=512 count=500 | od -c
Обратите внимание, что восьмеричные нули и нули ASCII это не одно и то же.
Создание устройств в Linux
В прошлом все устройства из каталога /dev создавались во время установки системы, а это означало, что каталог содержал все возможные поддерживаемые устройства, даже если они не использовались. Если вам нужно было создавать или переинициализировать файлы устройств, использовалась утилита mknod. Но для работы с ней вам нужно знать старший и младший номер устройства.
Сейчас ситуация изменилась и все файлы устройств linux создаются во время загрузки только для нужных устройств. Менеджер устройств следит за подключаемыми и отключаемыми устройствами и добавляет или удаляет соответствующие файлы. Вы можете убедиться, что устройства были созданы сейчас просмотрев дату создания в с помощью команды ls.
Команда mknod все еще есть, но уже существует более новая разработка — makedev. Она предоставляет очень простой интерфейс для создания устройств.
Выводы
В этой статье мы рассмотрели подключенные устройства linux, а также как выполняется работа с устройствами в Linux. Конечно, в одной статье невозможно полностью охватить такую огромную тему, но я надеюсь что у вас появились некоторые базовые навыки работы использования файлов устройств и эта статья была вам полезной.
Источник
Представление устройства в системе
В лекции Этапы загрузки системы говорилось о том, что аппаратный профиль компьютера определяется ядром на ранних этапах загрузки системы или в процессе подключения модуля. Это не означает, что устройство, не распознанное ядром, задействовать невозможно. Если неизвестным ядру устройством можно управлять по какому-нибудь стандартному протоколу, вполне возможно, что среди пакетов Linux найдётся утилита или служба, способная с этим устройством работать. Например, программа записи на лазерный диск cdrecord знает великое множество разнообразных устройств, отвечающих стандарту SCSI, в то время как ядро, как правило, только позволяет работать с таким устройством как с обычным лазерным приводом (на чтение), и передавать ему различные SCSI-команды.
К сожалению, иногда и обратное неверно: если производитель создаёт новое устройство, управлять которым нужно по-новому, а распознаётся оно как одно из старых, ошибки неизбежны. Многие стандарты внешних устройств предусматривают строгую идентификацию модели, однако хорошего мало и тут: незначительно изменив схемотехнику, производитель меняет и идентификатор, и устройство перестаёт распознаваться до тех пор, пока автор соответствующего модуля Linux не заметит это и не добавит новый идентификатор в список поддерживаемых.
Большинству распознанных устройств, если они должны поддерживать операции чтения/записи или хотя бы управления ( ioctl() , описанный ниже), соответствует файл-дырка в каталоге /dev или одном из его подкаталогов. В зависимости от того, выбрана ли в системе статическая или динамическая схема именования устройств, файлов-дырок в /dev может быть и очень много, и относительно мало. При статической схеме именования то, что ядро распознало внешнее устройство, никак не соотносится с тем, что в /dev имеется для этого устройства файл-дырка:
[root@localhost root]# cat /dev/sdg14
cat: /dev/sdg14: No such device or address
Пример 1. Обращение к несуществующему устройству
Здесь Мефодий попытался прочитать что-либо из устройства /dev/sdg14 , что соответствует четырнадцатому разделу SCSI-диска под номером семь. Такого диска в этой машине, конечно, нет, а файл-дырка для него заведён на всякий случай: вдруг появится? Поскольку появиться может любое из поддерживаемых Linux устройств, таких файлов «на всякий случай» в системе бывает и десять тысяч, и двадцать. Файл-дырка не занимает места на диске, однако использует индексный дескриптор, поэтому в корневой фаловой системе, независимо от её объёма, индексных дескрипторов должен быть изрядный запас.
При динамической схеме именования применяется специальная виртуальная файловая система, которая либо полностью подменяет каталог /dev , либо располагается в другом каталоге (например, /sys ), имеющем непохожую на /dev иерархизированную структуру; в этом случае файлы-дырки в /dev заводит специальная служба. Этот способ гораздо удобнее и для человека, который запустил команду ls /dev , и для компьютера (в случае подключения внешних устройств, например, съёмных жёстких дисков, «на лету»). Однако он требует соблюдать дополнительную логику «привязки» найденного устройства к имени, иногда весьма запутанную из-за той же нечёткой идентификации. Поскольку происходить это должно в самый ответственный момент, при загрузке системы, динамическую схему именования используют с осторожностью.
виртуальная файловая система Механизм отображения в виде файловой системы любых иерархически организованных данных. Существенно упрощает доступ к таким данным, так как позволяет применять обычные операции ввода-ввывода: открытие и закрытие файла, чтение и запись и т. п.
Файлы-дырки и другие типы файлов
Кое-какие идеи динамического именования устройств присутствуют и в статической схеме. Так, файлы /dev/mouse или /dev/cdrom , на самом деле — символьные ссылки на соответствующие файлы-дырки. Если тип мыши или лазерного привода изменится, достаточно изменить эти ссылки и перезапустить соответствующие службы.
[root@localhost root]# ls -l /dev/cdrom /dev/mouse
lrwxrwxrwx 1 root root 8 Nov 20 23:23 /dev/cdrom -> /dev/hdc
lrwxrwxrwx 1 root root 5 Nov 9 01:16 /dev/mouse -> psaux
[root@localhost root]# ls -lL /dev/cdrom /dev/mouse /dev/hda1 /dev/ur* /dev/ze*
brw-r—— 1 root cdrom 22, 0 Jul 26 16:59 /dev/cdrom
brw-rw—- 1 root disk 3, 1 Jul 26 16:59 /dev/hda1
crw——- 1 root root 10, 1 Dec 2 11:58 /dev/mouse
crw-r—r— 1 root root 1, 9 Nov 28 14:10 /dev/urandom
crw-rw-rw- 1 root root 1, 5 Jul 26 16:59 /dev/zero
Пример 2. Идентификация внешних устройства в /dev/
Файл-дырка, как и всякая дырка, не имеет никакого размера: сколько в неё не записывай, в файл на диске ничего не попадёт. Вместо этого ядро передаёт всё записанное драйверу, отвечающему за файл-дырку, а тот по-своему обрабатывает эти данные. Точно так же работает и чтение из файла-дырки: все запрашиваемые данные в неё подсовывает драйвер. Большинство драйверов — дисковые, звуковые последовательных и параллельных портов и т. п. — обращаются за данными к какому-нибудь внешнему устройству или передают их ему. Но есть и такие, кто сам всё выдумывает: это и /dev/null , чёрная дыра, в которую что угодно можно записать, и оно пропадёт безвозвратно, и /dev/zero , из которого можно считать сколько угодно нулей (на запись оно ведёт себя как /dev/null ), и /dev/urandom , из которого можно считать сколько угодно относительно случайных байтов.
Изучив выдачу команды ls -lL (ключ « -L » заставляет ls выводить информацию не про символьную ссылку, а про файл, на который она указывает), Мефодий обнаружил, что та вместо размера файла-дырки (который равен нулю) выводит два числа. Первое из этих чисел называется старшим номером устройства (major device number), оно, грубо говоря, соответствует драйверу, отвечающему за устройство. Второе называется младшим номером устройства (minor device number), оно соответствует способу работы с устройством, а для дисковых носителей — разделу. В частности, из примера видно, что устройствами /dev/random и /dev/urandom занимается один и тот же драйвер со старшим номером 1 . При этом часть устройств (по преимуществу — дисковые) имеет тип «b», а другая часть — «c» (этот тип имеют, например, терминалы). Тип указан в атрибутах файла первым символом. Это блочные (block) устройства, обмен данными с которыми возможен только порциями (блоками) определённого размера, и символьные (character) устройства, запись и чтение с которых происходит побайтно. Блочные устройства, вдобавок, могут поддерживать команды прямого доступа вида «прочитать блок номер такой-то » или «записать данные на диск, начиная с такого-то блока».
Блочные и символьные устройства — полноправные объекты файловой системы, такие же, как файлы, каталоги и символьные ссылки. Есть ещё два типа специальных файлов — каналы и сокеты. Канал-файл (или fifo) называют еще именованным каналом (named pipe): это такой же объект системы, как и тот, что используется командной оболочкой для организации конвейера (его называют неименованным каналом), разница между ними в том, что у fifo есть имя, он зарегистрирован в файловой системе. Это — типичный файл-дырка, причём дырка двухсторонняя: любая программа может записать в канал (если позволяют права доступа) и любая программа может оттуда прочитать. Создать именованный канал можно с помощью команды mkfifo :
$ mkfifo hole
methody@localhost:
$ ( date >> hole & head -1 /dev/null
Птн Дек 3 15:11:05 MSK 2004
methody@localhost:
$ ( cal >> hole & head -1 /dev/null
Декабря 2004
methody@localhost:
$ rm hole
Пример 3. Использование именованного канала
Здесь важно, что утилита head показывает начало не «файла» hole а именно последней записываемой порции данных, как и подобает трубе.
Если стандартный вывод ошибок всего конвейера перенаправлен в /dev/null , то командный интерпретатор не выводит сообщений о запуске и остановке фонового процесса.
канал Объект Linux, используемый в межпроцессном взаимодействии. Доступен в виде двух дескрипторов: один открыт на запись, другой — на чтение. Все данные, записываемые в первый дескриптор, немедленно можно прочитать из второго. Различают неименованный канал, уничтожаемый с закрытием обоих дескрипторов, и именованный канал (FIFO) — файл-дырку, создаваемый в файловой системе.
Что же касается сокетов, то это — более сложные объекты, предназначенные для связи двух процессов и передачи информации в обе стороны. Сокет можно представить в виде двух каналов (один «туда», другой «обратно»), однако стандартные файловые операции открытия/чтения/записи на нём не работают. Процесс, открывший сокет, считается сервером: он постоянно «слушает», нет ли в нём новых данных, а когда те появляются, счтывает их, обрабатывает, и, возможно, записывает в сокет ответ. Процесс-клиент может подключиться к сокету, обменяться информацией с процесом-сервером и отключиться. Точно так же можно передавать данные и по сети, в этом случае указывается не путь к сокету на файловой системе (т. н. unix domain socket), а сетевой адрес и порт удалённого компьютера (например internet socket, если подключаться с помошью сети Internet).
Драйверы устройств
Как уже говорилось в лекции Этапы загрузки системы, часть системы, отвечающая за взаимодействие с каким-нибудь внешним устройством и называемая «драйвер», в Linux либо входит в ядро, либо оформляется в виде модуля ядра, и подгружается по необходимости. Следовательно, файл-дырка, обращение к которому приводило к «no such device or address», вполне может и заработать (в этом одна из причин огромного количества устройств в /dev ). Гуревич наотрез отказался объяснять Мефодию «как добавить новый драйвер» до тех пор, пока тот не будет лучше разбираться в архитектуре компьютеров вообще и в аппаратной части IBM-совместимых компьютеров в частности. Поэтому всё, что смог понять Мефодий, не имея таких знаний, сводилось к следующему. Во-первых, если существуют различия между тем, как по умолчанию загружает модули система и тем, как на самом деле это необходимо делать, различия должны быть описаны в файле /etc/modules.conf . Во-вторых, после изменения этого файла, добавления нового устройства, обновления самих модулей и т. п. следует запускать утилиту depmod , которая заново выстраивает непротиворечивую последовательность загрузки модулей. В-третьих, интересно (но в отсутствие знаний — малопознавательно) запускать утилиту lspci , которая показывает список устройств (распознаваемых по стандарту PCI), найденных на компьютере.
Работа с устройствами
Все файлы-дырки подчиняются одним и тем же правилам работы с файлами: их можно открывать для записи или чтения, записывать данные или считывать их стандартными средствами, а по окончании работы — закрывать. Открытие и закрытие файла (системные вызовы open() и close() ) в командном интерпретаторе не представлено отдельной операцией, оно выполняется автоматически при перенаправлении ввода (открытие на чтение) или вывода (на запись). Это позволяет работать и с устройствми, и с каналами, и с файлами совершенно одинаково, что активно используется в Linux программами-фильтрами. Каждый тип файлов имеет свою специфику, например, при записи на блочное устройство данные накапливаются ядром в специальном буфере размером в один блок, и только после заполнения буфера записываются. Если при закрытии файла буфер неполон, он всё равно передаётся целиком: часть — данные, записанные пользователем, часть — данные, оставшиеся от предыдущей операции записи). Это, конечно, не означает, что из файла, находящегося на блочном устройстве, легко по ошибке прочитать такой «мусор»: длина файла известна, и ядро само следит за тем, чтобы программа не прочла лишнего.
Даже такие (казалось бы) простые устройства, как жёсткие диски, поддерживают гораздо больше различных операций, чем просто чтение или запись. Пользователю, как минимум, может потребоваться узнать размер блока (для разных типов дисков он разный) или объём всего диска в блоках. Для многих устройств собственно передача данных — лишь итог замысловатого общения с управяющей программой или ядром. Скажем, для вывода оцифрованного звука на звуковую карту сначала необходимо настроить параметры звукогенератора: частоту, размер шаблона, количество каналов, формат передаваемых данных и многое другое. Для управления устройствами существует системный вызов ioctl() (iput-output control): устройство надо открыть, как файл, а затем использовать эту функцию. У каждого устройства — свой набор команд управления, поэтому в виде отдельной утилиты ioctl() не встречается, а используется неявно другими утилитами, специализирующимися на определённом типе устройств.
Права доступа к устройствам
Некоторые устройства просто обязаны быть доступны ползователю на запись и чтение. Например, виртуальная консоль, за которой работает Мефодий, доступна пользователю methody на запись и на чтение, именно поэтому команднный интерпретатор Мефодия может посылать туда символы и считывать их оттуда. В то же время, терминал, за которым работает Гуревич, пользователю недоступен, а терминалы, за которыми не работает никто, доступны только суперпользователю:
$ who
methody tty1 Dec 3 16:02 (localhost)
shogun ttyS0 Dec 3 16:03 (localhost)
methody@localhost
$ ls -l /dev/tty1 /dev/tty2 /dev/ttyS0
crw—w—- 1 methody tty 4, 1 Дек 3 16:02 /dev/tty1
crw——- 1 root root 4, 2 Дек 3 15:51 /dev/tty2
crw—w—- 1 shogun tty 4, 64 Дек 3 16:03 /dev/ttyS0
methody@localhost:
$ ls -l /usr/bin/write
-rwx—s—x 1 root tty 8708 Июн 25 14:00 /usr/bin/write
Пример 4. Кому принадлежат терминалы?
Права на владение терминалом передаются с помощью chown пользователю программой login после успешной региситрации в системе. Она же выставляет право записи на терминал членам группы tty. «Настоящих» пользователей в этой группе может и не быть, зато есть setGID-программы, например, write , которая умеет выводить сообщения сразу на все активные терминалы.
Множество устройств в системе, используемой как рабочая станция, также отдаются во владение — на этот раз, первому пользователю, зарегистрировавшемуся в системе. Предполагается, что компьютер служит в качестве рабочей станции именно этого пользователя, а все последующие доступа к этим устройствам не получат.
Что называется, «кто первым встал — того и тапки».
Как правило, так поступают с устройствами, которые могут понадобиться только одному человеку, сидящему за монитором: звуковыми и видеокартами, лазерными приводами, дисководом и т. п.:
$ ls -l /dev | grep methody | wc
665 6649 41459
shogun@localhost
$ ls -lL /dev/
Пример 5. Кому принадлежат устройства?
При этом для того, чтобы обеспечить и другим — псевдо- или настоящим — пользователям, такие устройства также принадлежат определённым группам с соответствующими правами. Практика «раздачи» устройств группам вообще очень удобна: даже если доступ к устройству имеет только суперпользователь, существует возможность написать setGID-программу, которая, не получая суперпользовательских прав, сможет до этого устройства добраться (а можно и просто включить опытного пользователя в такую группу).
Источник