Функционирование системы UNIX
Выполнение процессов
Процесс может выполняться в одном из двух состояний, а именно пользовательском и системном. В пользовательском состоянии процесс выполняет пользовательскую программу и имеет доступ к пользовательскому сегменту данных. В системном состоянии процесс выполняет программы ядра и имеет доступ к системному сегменту данных.
Когда пользовательскому процессу требуется выполнить системную функцию, он создает системный вызов. Фактически происходит вызов ядра системы как подпрограммы. С момента появления системного вызова процесс считается системным. Таким образом, пользовательский и системный процессы являются двумя фазами одного и того же процесса, но они никогда не пересекаются между собой. Каждая фаза пользуется своим собственным стеком. Стек задачи содержит аргументы, локальные переменные и другую информацию относительно функций, выполняемых в режиме задачи. Диспетчерский процесс не имеет пользовательской фазы.
В UNIX-системах используется разделение времени, то есть каждому процессу выделяется квант времени. Либо процесс завершается сам до истечения отведенного ему кванта времени, либо он откладывается по истечении кванта. Механизм диспетчеризации характеризуется достаточно справедливым распределением процессорного времени между всеми процессами. Пользовательским процессам приписываются приоритеты в зависимости от количества получаемого ими процессорного времени. Процессам, которые получили большое количество процессорного времени, назначают более низкие приоритеты, в то время как процессам, которые получили лишь небольшое количество процессорного времени, – наоборот, повышают приоритет. Такой метод диспетчеризации обеспечивает хорошее время реакции для всех пользователей системы. Все системные процессы имеют более высокие приоритеты по сравнению с пользовательскими и поэтому всегда обслуживаются в первую очередь.
Подсистема ввода/вывода
Функции ввода/вывода в UNIX задаются в основном с помощью пяти системных вызовов, а именно: open, close, read, write и seek.
Те же самые команды ввода/вывода применяются и к физическим устройствам. В системе UNIX физические устройства представлены специальными файлами в единой структуре файловой системы. Это означает, что пользователь не может написать зависящую от устройств программу, если только эта зависимость не отражена в самом потоке передаваемых данных. Стандартные файлы ввода и вывода, приписываемые пользовательскому терминалу, открывать обычным путем не требуется. Терминал открывается автоматически по команде входа в систему – login.
Система ввода/вывода UNIX, в отличие от большинства других систем, ориентирована скорее на работу с потоком, а не с записями. Здесь поток (stream) – это последовательность байтов, заканчивающаяся разделителем (то есть символом конца потока end-of-stream). Понятие потока позволяет проще добиться независимости от устройств и унификации файлов с физическими устройствами и транспортерами (конвейерами). Тем самым пользователь получает гибкость в работе с группами данных, но на него ложатся и дополнительные заботы, поскольку ему приходится писать программы управления данными. Пользователь может при необходимости относительно легко самостоятельно реализовать работу с записями. Чтобы работать с записями фиксированной длины, достаточно просто задавать постоянную длину во всех командах чтения и записи. Прямой доступ при фиксированной длине записей получается путем умножения длины записи на номер записи и выполнения команды seek для нахождения позиций нужной записи. Работу с записями переменной длины можно организовать, если разместить в начале каждой записи поле фиксированного размера, содержащее длину записи.
Перенаправление ввода/вывода
Механизм перенаправления ввода/вывода является одним из наиболее элегантных, мощных и одновременно простых механизмов ОС UNIX. Цель, которая ставилась при разработке этого механизма, состоит в следующем. Поскольку UNIX это интерактивная система, которая создавалась в конце 60-х – начале 70-х годов, то обычно программы вводили текстовые строки с терминала и выводили результирующие текстовые строки на экран терминала. Для того чтобы обеспечить более гибкое использование таких программ, желательно было уметь обеспечить им ввод из файла или из вывода других программ и направить их вывод в файл или на ввод другим программам.
Реализация этого механизма основывается на следующих свойствах ОС UNIX. Во-первых, любой ввод/вывод трактуется как ввод из некоторого файла и вывод в некоторый файл. Клавиатура и экран терминала тоже интерпретируются как файлы (первый можно только читать, а во второй можно только писать). Во-вторых, доступ к любому файлу производится через его дескриптор (положительное целое число). Фиксируются три значения дескрипторов файлов. Файл с дескриптором 1 называется файлом стандартного ввода (std1n), файл с дескриптором 2 – файлом стандартного вывода (stdout) и файл с дескриптором 3 – файлом стандартного вывода диагностических сообщений (stderr). В-третьих, программа, запущенная в некотором процессе, «наследует» от породившего процесса все дескрипторы открытых файлов.
В головном процессе интерпретатора командного языка файлом стандартного ввода является клавиатура терминала пользователя, а файлами стандартного вывода и вывода диагностических сообщений – экран терминала. Однако при запуске любой команды можно сообщить интерпретатору (средствами соответствующего командного языка), какой файл или вывод какой программы должен служить файлом стандартного ввода для запускаемой программы и какой файл или ввод какой программы должен служить файлом стандартного вывода или вывода диагностических сообщений для запускаемой программы.
Файловая система
Структура файловой системы
Файл в системе UNIX представляет собой множество символов с произвольным доступом. В файле содержатся произвольные данные, помещенные туда пользователем, и файл не имеет никакой другой структуры, кроме той, какую налагает на него пользователь.
Рассмотрим одну из первых реализаций файловой системы, поскольку основные ее идеи сохраняются до сих пор.
Информация на дисках размещается поблочно, по 512 байт в каждом блоке. Диск разбивается на следующие области (рис. 5.2):
неиспользуемый блок;
управляющий блок или суперблок, в котором содержится размер диска и границы других областей;
i-список, состоящий из описаний файлов, называемых i-узлами;
область для хранения содержимого файлов.
Каждый i-узел содержит:
идентификацию владельца;
идентификацию группы владельца;
биты защиты;
физические адреса на диске или ленте, где находится содержимое файла;
размер файла;
время создания файла;
время последнего использования файла (modification time);
время последнего изменения атрибутов (change time);
число связей-ссылок, указывающих на файл;
индикацию, является ли файл директорией, обычным файлом или специальным файлом.
Следом за i-списком идут блоки, предназначенные для хранения содержимого файлов. Пространство на диске, оставшееся свободным от файлов, образует связанный список свободных блоков.
Таким образом, файловая система UNIX представляет собой структуру данных, размещенную на диске и содержащую управляющий суперблок, в котором определена файловая система в целом; массив i‑узлов, где определены все файлы в файловой системе; сами файлы; и, наконец, совокупность свободных блоков. Выделение пространства под данные осуществляется блоками фиксированного размера.
Каждый файл однозначно идентифицируется старшим номером устройства, младшим номером устройства и i-номером (индексом i‑узла данного файла в массиве i-узлов). Когда вызывается драйвер устройства, по старшему номеру индексируется массив входных точек в драйверы. По младшему номеру драйвер выбирает одно устройство из группы идентичных физических устройств.
Файл-директория, в котором перечислены имена файлов, позволяет установить соответствие между именами и самими файлами. Директории образуют древовидную структуру. На каждый обычный файл или файл устройства могут иметься ссылки в различных узлах этой структуры. В непривилегированных программах запись в директории не разрешена, но при наличии соответствующих разрешений они могут читать их. Дополнительных связей между директориями нет.
Большое число системных директорий система UNIX использует для своих собственных нужд. Одна из них, корневая директория, является базой для всей структуры директорий, и, «отталкиваясь» от нее, можно найти размещение всех файлов. В других системных директориях содержатся программы и команды, предоставляемые пользователям, и файлы устройств.
Имена файлов задаются последовательностью имен директорий, разделенных косой чертой («/») и приводящих к концевому узлу (листу) некоторого дерева.
Файл, не являющийся директорией, может встречаться в различных директориях, возможно, под разными именами. Это называется связыванием. Элемент в директории, относящийся к одному файлу, называется связью. В системе UNIX все такие связи имеют равный статус. Файлы не принадлежат директориям. Скорее, файлы существуют независимо от элементов директорий, а связи в директориях указывают действительно на физические файлы. Файл «исчезает», когда удаляется последняя связь, указывающая на него. Биты защиты, заданные в связях, могут отличаться от битов в исходном файле. Таким образом, решается проблема избирательного ограничения доступа к файлам.
С каждым поддерживаемым системой устройством ассоциируется один или большее число специальных файлов. Операции ввода/вывода для специальных файлов осуществляются так же, как и для обычных дисковых файлов, с той лишь разницей, что эти операции активизируют соответствующие устройства. Специальные файлы обычно находятся в справочнике /dev. На специальные файлы могут указывать связи точно так же, как на обычные файлы.
От файловой системы не требуется, чтобы она вся целиком размещалась на том устройстве, где находится корень. Запрос от системы mount (на установку носителей и т. п.) позволяет встраивать в иерархию файлов файлы на сменных томах. В результате выполнения команды mount файловая система, расположенная на указанном устройстве, подключается к системе таким образом, что ее содержимое заменяет собой содержимое заданного в команде каталога. Команда umount выполняет обратную операцию – «отсоединяет» (размонтирует) файловую систему, после чего диск с данными можно физически извлечь из системы. Например, для записи данных на дискету необходимо ее смонтировать, а после работы – размонтировать.
Защита файлов
Защита файлов осуществляется при помощи номера, идентифицирующего пользователя, и установки десяти битов защиты – атрибутов доступа. Права доступа подразделяются на три типа: чтение (read), запись (write) и выполнение (execute). Эти типы прав доступа могут быть предоставлены трем классам пользователей: владельцу файла, группе, в которую входит владелец, и всем (прочим) пользователям. Файл всегда связан с определенным пользователем – своим владельцем – и с определенной группой, то есть у него есть уже UID (user ID, идентификатор пользователя) и GID (group ID, идентификатор группы). Изменять права доступа к файлу разрешено только его владельцу. Изменить владельца файла может суперпользователь, группу – суперпользователь или владелец файла.
Программа, выполняющаяся в системе, всегда запускается от имени какого-то пользователя и какой-то группы (обычно – основной группы этого пользователя), но связь процессов с пользователями и группами организована сложнее: здесь различаются идентификатор для доступа к файловой системе (FSUID – file system access user ID, FSGID – file system access group ID) и эффективный идентификатор (EUID – effective user ID, EGID – effective group ID), а при доступе к файлам учитываются еще и полномочия (capabilities), присвоенные самому процессу.
При создании файл получает UID, совпадающий с FSUID процесса, который его создает, и, как правило, GID, совпадающий с FSGID этого процесса.
Атрибуты доступа определяют, что разрешено делать с данным файлом данной категории пользователей. Имеются всего три операции: чтение, запись и выполнение.
При создании файла (или еще одного имени для уже существующего файла) модифицируется не сам файл, а каталог, в котором появляются новые ссылки на узлы. Удаление файла заключается в удалении ссылки. Таким образом, право на создание или удаление файла – это право на запись в каталог.
Право на выполнение каталога интерпретируется как право на поиск в нем (прохождение через него). Оно позволяет обратиться к файлу по пути, содержащему данный каталог, даже тогда, когда каталог не разрешено читать и список всех его файлов поэтому недоступен.
Помимо трех названных основных атрибутов доступа существуют дополнительные, используемые в следующих случаях. Атрибуты SUID и SGID существенны при запуске программы на выполнение; они требуют, чтобы программа выполнялась не от имени запустившего ее пользователя (группы), а от имени владельца (группы) того файла, в котором она находится. Выражаясь формально, если файл программы имеет атрибут SUID (SGID), то FSUID и EUID (FSGID и EGID) соответствующего процесса не наследуются от процесса, запустившего его, а совпадают с UID (GID) файла. Благодаря этому пользователи получают возможность запустить системную программу, которая создает свои рабочие файлы в закрытых для них каталогах.
Кроме того, если процесс создает файл в каталоге, имеющем атрибут SGID, то файл получает GID не по FSGID процесса, а по GID каталога. Это удобно для коллективной работы: все файлы и подкаталоги в каталоге автоматически оказываются принадлежащими одной и той же группе, хотя создавать их могут разные пользователи. Есть еще один атрибут – CVTX, который теперь относится к каталогам. Он показывает, что из каталога, имеющего этот атрибут, ссылку на файл может удалить только владелец файла.
Существуют две стандартные формы записи прав доступа – символьная и восьмеричная. Символьная представляет собой цепочку из десяти знаков, первый из которых не относится собственно к правам, а обозначает тип файла. Используются следующие обозначения:
«-» – обычный файл;
«d» – каталог (директория);
«с» – символьное устройство;
«b» – блочное устройство;
«р» – именованный канал (named pipe);
«s» – «гнездо» (socket);
«I» – символическая ссылка.
Далее следуют три последовательности, каждая из трех символов, соответствующие правам пользователя, группы и всех остальных. Наличие права на чтение обозначается буквой «r», на запись – «w», на выполнение – «х», отсутствие какого-либо права – знаком «-» в соответствующей позиции.
Наличие атрибута SUID (SGID) обозначается заглавной буквой «S» в позиции права на выполнение для владельца (группы), если выполнение не разрешено, и прописной буквой «s», если разрешено.
Восьмеричная запись – это шестизначное число, первые два знака которого обозначают тип файла и довольно часто опускаются, третья цифра – атрибуты GUID (4), SGID (2) и SVTX (1), а оставшиеся три – соответственно права владельца, группы и всех остальных. Очевидно, что право на чтение можно представить числом «4», право на запись – числом «2», а право на выполнение кодируется как «1». Например, стандартный набор прав доступа для каталога /tmp в символьной форме выглядит как drwxrwxrwt, а в восьмеричной – как 041777 (это каталог; чтение, запись и поиск разрешены всем; установлен атрибут SVTX). А набор прав -r-S-xw-, или в числовом виде – 102412, будет означать, что это обычный файл, владельцу разрешается читать его, но не выполнять и не изменять; пользователям из группы файла (за исключением владельца) – выполнять (причем во время работы программа получит права владельца файла), но не читать и не изменять; а всем остальным – изменять, но не читать и не выполнять.