Файл: А. В. Гордеев А. Ю. Молчанов системное программное обеспечение электронный вариант книги издательства Питер СанктПетербург Челябинск юургу каф. Автоматика и управление 2002 2 Предисловие Настоящий учебник.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 12.01.2024

Просмотров: 1066

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

403
к поиску директории аlех в директории work и, наконец, к поиску элемента stuff в директории аlех. Сама по себе косая черта / обозначает корневую директорию. В
приведенном примере нашла отражение типичная иерархическая структура файло- вой системы, например, work может обозначать диск (устанавливаемый при работе пользователя), аlех может быть директорией пользователя, a stuff может принадле- жать аlех.
Файл, не являющийся директорией, может встречаться в различных директо- риях, возможно, под разными именами. Это называется связыванием. Элемент в директории, относящийся к одному файлу, называется связью. В системе UNIX все такие связи имеют равный статус. Файлы не принадлежат директориям. Скорее,
файлы существуют независимо от элементов директорий, а связи в директориях указывают действительно на физические файлы. Файл «исчезает», когда удаляется последняя связь, указывающая на него. Биты защиты, заданные в связях, могут от- личаться от битов в исходном файле. Таким образом, решается проблема избира- тельного ограничения доступа к файлам.
С каждым поддерживаемым системой устройством ассоциируется один или большее число специальных файлов. Операции ввода/вывода для специальных файлов осуществляются так же, как и для обычных дисковых файлов, с той лишь разницей, что эти операции активизируют соответствующие устройства. Специ- альные файлы обычно находятся в справочнике /dev. На специальные файлы могут указывать связи точно так же, как на обычные файлы.
От файловой системы не требуется, чтобы она вся целиком размещалась на том устройстве, где находится корень. Запрос от системы mount (на установку но- сителей и т. п.) позволяет встраивать в иерархию файлов файлы на сменных томах.
Команда mount имеет несколько опций, но обязательных аргументов у стандартно- го варианта её использования два: имя файла блочного устройства и имя каталога.
В результате выполнения этой команды файловая система, расположенная на ука- занном устройстве, подключается к системе таким образом, что ее содержимое за- меняет собой содержимое заданного в команде каталога. Поэтому для монтирова-
ния соответствующего тома обычно используют пустой каталог. Команда umount

404
выполняет обратную операцию – «отсоединяет» (размонтирует) файловую систе- му, после чего диск с данными можно физически извлечь из системы. Например,
для записи данных на дискету необходимо её смонтировать, а после работы – раз- монтировать.
Защита файлов
Защита файлов осуществляется при помощи номера, идентифицирующего пользователя, и установки десяти битов защиты – атрибутов доступа. Права досту- па подразделяются на три типа: чтение (read), запись (write) и выполнение (exe- cute). Эти типы прав доступа могут быть предоставлены трём классам пользовате- лей:
владельцу файла, группе, в которую входит владелец, и всем (прочим) пользо- вателям. Девять из этих битов управляют защитой по чтению, записи и исполне- нию для владельца файла, других членов группы, в которую входит владелец, и всех других пользователей. Файл всегда связан с определенным пользователем –
своим владельцем – и с определенной группой, то есть у него есть уже известные нам 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 этого процесса. Атрибуты доступа определяют, что разрешено делать с данным файлом данной категории пользователей. Имеются всего три операции: чтение, запись и выполнение.


405
При создании файла (или ещё одного имени для уже существующего файла)
модифицируется не сам файл, а каталог, в котором появляются новые ссылки на узлы. Удаление файла заключается в удалении ссылки. Таким образом, право на создание или удаление файла – это право на запись в каталог.
Право на выполнение каталога интерпретируется как право на поиск в нём
(прохождение через него). Оно позволяет обратиться к файлу по пути, содержаще- му данный каталог, даже тогда, когда каталог не разрешено читать и список всех его файлов поэтому недоступен.
Помимо трёх названных основных атрибутов доступа существуют дополни- тельные, используемые в следующих случаях. Атрибуты SUID и SGID существен- ны при запуске программы на выполнение: они требуют, чтобы программа выпол- нялась не от имени запустившего ее пользователя (группы), а от имени владельца
(группы) того файла, в котором она находится. Выражаясь формально, если файл программы имеет атрибут SUID (SGID), то FSUID и EUID (FSGID и EGID) соот- ветствующего процесса не наследуются от процесса, запустившего его, а совпада- ют с UID (GID) файла. Благодаря этому пользователи получают возможность за- пустить системную программу, которая создает свои рабочие файлы в закрытых для них каталогах.
Кроме того, если процесс создает файл в каталоге, имеющем атрибут SGID, то файл получает GID не по FSGID процесса, а по GID каталога. Это удобно для кол- лективной работы: все файлы и подкаталоги в каталоге автоматически оказывают- ся принадлежащими одной и той же группе, хотя создавать их могут разные поль- зователи. Есть еще один атрибут – CVTX, который теперь относится к каталогам.
Он показывает, что из каталога, имеющего этот атрибут, ссылку на файл может удалить только владелец файла.
Существуют две стандартные формы записи прав доступа – символьная и восьмеричная. Символьная представляет собой цепочку из десяти знаков, первый из которых не относится собственно к правам, а обозначает тип файла. Использу- ются следующие обозначения:
♦ «-» – обычный файл;

406
♦ «d» – каталог (директория);
♦ «с» – символьное устройство;
♦ «b» – блочное устройство;
♦ «р» – именованный канал (named pipe);
♦ «s» – «гнездо» (socket
1
);
♦ «I» – символическая ссылка.
Далее следуют три последовательности, каждая из трёх символов, соответст- вующие правам пользователя, группы и всех остальных. Наличие права на чтение обозначается буквой «r», на запись – «w», на выполнение – «х», отсутствие какого–
либо права – знаком «-» в соответствующей позиции.
Наличие атрибута SUID (SGID) обозначается заглавной буквой «S» в позиции права на выполнение для владельца (группы), если выполнение не разрешено, и прописной буквой «s», если разрешено.
Восьмеричная запись – это шестизначное число, первые два знака которого обозначают тип файла и довольно часто опускаются, третья цифра – атрибуты
GUID (4), SGID (2) и SVTX (1), а оставшиеся три – соответственно права владель- ца, группы и всех остальных. Очевидно, что право на чтение можно представить числом «4», право на запись – числом «2», а право на выполнение кодируется как
«1».
Например, стандартный набор прав доступа для каталога /tmp в символьной форме выглядит как drwxrwxrwt, а в восьмеричной – как 041777 (это каталог; чте- ние, запись и поиск разрешены всем; установлен атрибут SVTX). А набор прав -r-
S-xw-, или в числовом виде – 102412, будет означать, что это обычный файл, вла- дельцу разрешается читать его, но не выполнять и не изменять; пользователям из группы файла (за исключением владельца) – выполнять (причём во время работы программа получит права владельца файла), но не читать и не изменять; а всем ос- тальным – изменять, но не читать и не выполнять.
1
Socket – это понятие, связанное со стеком протоколов TCP/IP, который является «родным» для UNIX. Его следует понимать как некий адрес или порт, через который связываются удаленные программы.


407
Большинство программ создают файлы с разрешением на чтение и запись для всех пользователей, а каталоги – с разрешением на чтение, запись и поиск для всех пользователей. Этот исходный набор атрибутов логически складывается с «пользо- вательской маской» – user file-creation mask, сокращенно umask, которая обычно ограничивает доступ. Например, следующие значения для umask u=rwx, g=rwx,
o=r-x следует понимать так: у владельца и группы остается полный набор прав, а всем остальным запрещается запись. В восьмеричном виде оно запишется как 002
(первая цифра – ограничения для владельца, вторая – для группы, третья – для ос- тальных, запрещение чтения – 4, записи – 2, выполнения – 1). Владелец файла мо- жет изменить права доступа к нему командой chmod.
Межпроцессные коммуникации в UNIX
ОС UNIX в своей основе наиболее полно отвечает требованиям технологии
«клиент–сервер». Эта универсальная модель служит основой построения любых сколь угодно сложных систем, в том числе и сетевых. Разработчики СУБД, комму- никационных систем, систем электронной почты, банковских систем и т. д. во всем мире широко используют технологию «клиент–сервер». Для построения про- граммных систем, работающих по принципам модели типа «клиент–сервер» в
UNIX существуют следующие механизмы:
♦ сигналы;
♦ семафоры;
♦ программные каналы;
♦ очереди сообщений;
♦ сегменты разделяемой памяти;
♦ вызовы удаленных процедур.
Многие из этих механизмов нам уже знакомы, поэтому рассмотрим их вкрат- це.
Сигналы
Если рассматривать выполнение процесса в виртуальном компьютере, кото- рый предоставляется каждому пользователю, то в такой системе должна существо- вать система прерываний, отвечающая стандартным требованиям:

408
♦ обработка исключительных ситуаций;
♦ средства обработки внешних и внутренних прерываний;
♦ средства управления системой прерываний (маскирование и демаскирова- ние).
Всем этим требованиям в UNIX отвечает техника сигналов, которая может не только воспринимать и обрабатывать сигналы, но и порождать их и посылать на другие машины (процессы). Сигналы могут быть синхронными, когда инициатор сигнала – сам процесс, и асинхронными, когда инициатор возникновения сигнала –
интерактивный пользователь за терминалом. Источником асинхронных сигналов может быть также ядро, когда оно контролирует определенные состояния аппара- туры, рассматриваемые как ошибочные.
Сигналы можно рассматривать как простейшую форму межпроцессного взаи- модействия, которое используется для передачи от одного процесса другому или от ядра ОС какому–либо процессу уведомления о возникновении определенного со- бытия.
Семафоры
Механизм семафоров, реализованный в ОС UNIX, является обобщением клас- сического механизма семафоров общего вида, предложенного известным голланд- ским специалистом профессором Дейкстрой. Семафор в ОС UNIX состоит из сле- дующих элементов:
♦ значение семафора;
♦ идентификатор процесса, который хронологически последним работал с се- мафором;
♦ число процессов, ожидающих увеличения значения семафора;
♦ число процессов, ожидающих нулевого значения семафора.
Для работы с семафорами имеются следующие три системных вызова:
♦ semget – для создания и получения доступа к набору семафоров;
♦ semop – для манипулирования значениями семафоров (с помощью именно этого системного вызова осуществляют синхронизацию процессов на основе ис- пользования семафоров);


409
♦ semctl – для выполнения разнообразных управляющих операций над набо- ром семафоров.
Системный вызов semget имеет следующий синтаксис:
id = semget(key, count, flag);
где параметры key и flag и возвращаемое значение системного вызова (id)
имеют тот же смысл, что для других системных вызовов семейства «
get
», а пара- метр count задает число семафоров в наборе семафоров, обладающих одним и тем же ключом. После этого индивидуальный семафор идентифицируется дескрипто- ром набора семафоров и номером семафора в этом наборе. Если к моменту вы- полнения системного вызова semget набор семафоров с указанным ключом уже существует, то обращающийся процесс получит соответствующий дескриптор, но так и не узнает о реальном числе семафоров в группе (хотя позже это все-таки можно узнать с помощью системного вызова semctl
).
Основным системным вызовом для манипулирования семафором является se- mop
:
oldval = semop(id,oplist, count);
где id
– это ранее полученный дескриптор группы семафоров, орlist
– массив описателей операций над семафорами группы, a count
– размер этого массива. Зна- чение, возвращаемое системным вызовом, является значением последнего обрабо- танного семафора. Каждый элемент массива орlist имеет следующую структуру:
♦ номер семафора в указанном наборе семафоров;
♦ операция;
♦ флаги.
Если проверка прав доступа проходит нормально и указанные в массиве орlist номера семафоров не выходят за пределы общего размера набора семафоров, то системный вызов выполняется следующим образом. Для каждого элемента массива орlist значение соответствующего семафора изменяется в соответствии со значени- ем поля «операция»:

410
♦ если значение поля операции положительно, то значение семафора увели- чивается на единицу, а все процессы, ожидающие увеличения значения семафора,
активизируются (пробуждаются в терминологии UNIX);
♦ если значение поля операции равно нулю, то если значение семафора также равно нулю, выбирается следующий элемент массива орlist
. Если же значение се- мафора отлично от нуля, то ядро увеличивает на единицу число процессов, ожи- дающих нулевого значения семафора, а обратившийся процесс переводится в со- стояние ожидания (усыпляется в терминологии UNIX);
♦ если значение поля операции отрицательно и его абсолютное значение меньше или равно значению семафора, то ядро прибавляет это отрицательное зна- чение к значению семафора. Если в результате значение семафора стало нулевым,
то ядро активизирует (пробуждает) все процессы, ожидающие нулевого значения этого семафора. Если же значение семафора меньше абсолютной величины поля операции, то ядро увеличивает на единицу число процессов, ожидающих увеличе- ния значения семафора, и откладывает (усыпляет) текущий процесс до наступле- ния этого события.
Интересно заметить, что основным поводом для введения массовых операций над семафорами было стремление дать программистам возможность избегать ту- пиковых ситуаций в связи с семафорной синхронизацией. Это обеспечивается тем,
что системный вызов semop
, каким бы длинным он ни был (по причине потенци- ально неограниченной длины массива орlist
), выполняется как атомарная операция,
то есть во время выполнения semop ни один другой процесс не может изменить значение какого-либо семафора.
Наконец, среди флагов-параметров системного вызова semop может содер- жаться флаг с символическим именем IPC_NOWAIT, наличие которого заставляет ядро ОС UNIX не блокировать текущий процесс, а лишь сообщать в ответных па- раметрах о возникновении ситуации, которая может привести к блокированию процесса при отсутствии флага IPC_NOWAIT. Мы не будем обсуждать здесь воз- можности корректного завершения работы с семафорами при незапланированном завершении процесса; заметим только, что такие возможности обеспечиваются.


411
Системный вызов semctl имеет формат semctl (id, number, cmd, arg);
где id
– это дескриптор группы семафоров, number
– номер семафора в группе,
cmd
– код операции, а arg
– указатель на структуру, содержимое которой интерпре- тируется по-разному, в зависимости от операции. В частности, с помощью semctl можно уничтожить индивидуальный семафор в указанной группе. Однако детали этого системного вызова настолько громоздки, что мы рекомендуем в случае необ- ходимости обращаться к технической документации используемого варианта опе- рационной системы.
Программные каналы
Мы с вами уже знакомились с программными каналами в главе 6. Однако рас- смотрим этот механизм ещё раз, так сказать в его исходном, изначальном толкова- нии.
Программные каналы (pipes) в ОС UNIX являются очень важным средством взаимодействия и синхронизации процессов. Теоретически программный канал по- зволяет взаимодействовать любому числу процессов, обеспечивая дисциплину
FIFO (first-in-first-out). Другими словами, процесс, читающий из программного ка- нала, прочитает самые давние записанные в программный канал данные. В тради- ционной реализации программных каналов для хранения данных использовались файлы. В современных версиях ОС UNIX для реализации программных каналов применяются другие средства IPC (в частности, очереди сообщений).
В UNIX различаются два вида программных каналов – именованные и неиме- нованные. Именованный программный канал может служить для общения и син- хронизации произвольных процессов, знающих имя данного программного канала и имеющих соответствующие права доступа. Неименованным программным кана- лом могут пользоваться только создавший его процесс и его потомки (необяза- тельно прямые).
Для создания именованного программного канала (или получения к нему дос- тупа) используется обычный файловый системный вызов open
. Для создания же неименованного программного канала существует специальный системный вызов pipe
(исторически более ранний). Однако после получения соответствующих деск-

412
рипторов оба вида программных каналов используются единообразно с помощью стандартных файловых системных вызовов read
, write и close
Системный вызов pipe имеет следующий синтаксис:
plpe(fdptr);
где fdptr
– это указатель на массив из двух целых чисел, в который после соз- дания неименованного программного канала будут помещены дескрипторы, пред- назначенные для чтения из программного канала (с помощью системного вызова read
) и записи в программный канал (с помощью системного вызова write
). Деск- рипторы неименованного программного канала – это обычные дескрипторы фай- лов, то есть такому программному каналу соответствуют два элемента таблицы от- крытых файлов процесса. Поэтому при последующем использовании системных вызовов read и write процесс совершенно не обязан отличать случай использования программных каналов от случая использования обычных файлов (собственно, на
этом и основана идея перенаправления ввода/вывода и организации конвейеров).
Для создания именованных программных каналов (или получения доступа к уже существующим каналам) используется обычный системный вызов open
. Ос- новным отличием от случая открытия обычного файла является то, что если име- нованный программный канал открывается на запись и ни один процесс не открыл тот же программный канал для чтения, то обращающийся процесс блокируется до тех пор, пока некоторый процесс не откроет данный программный канал для чте- ния. Аналогично обрабатывается открытие для чтения.
Запись данных в программный канал и чтение данных из программного канала
(независимо от того, именованный он или неименованный) выполняются с помо- щью системных вызовов read и write
. Отличие от случая использования обычных файлов состоит лишь в том, что при записи данные помещаются в начало канала, а при чтении выбираются (освобождая соответствующую область памяти) из конца канала.
Окончание работы процесса с программным каналом (независимо от того,
именованный он или неименованный) производится с помощью системного вызова close