Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Привилегированный пользователь



Ядро ОС UNIX идентифицирует каждого пользователя по его идентификатору (UID – user identifier), уникальному целому значению, присваиваемому пользователю при регистрации в системе. Кроме того, каждый пользователь относится к некоторой группе пользователей, которая также идентифицируется некоторым целым значением (GID – group identifier). Значения UID и GID для каждого зарегистрированного пользователя сохраняются в учётных файлах системы и при­писываются процессу, в котором выполняется командный интерпретатор, запу­щенный при входе пользователя в систему. Эти значения наследуются каждым новым процессом, запущенным от имени данного пользователя, и используют­ся ядром системы для контроля правомочности доступа к файлам, выполнения программ и т. д.

Очевидно, что администратор системы, который тоже является зарегистрирован­ным пользователем, должен обладать большими возможностями, чем обычные пользователи. В ОС UNIX эта задача решается путём выделения единственного нулевого значения UID. Пользователь с таким UID называется суперпользова­телем (superuser) или root. Он имеет неограниченные права на доступ к любому файлу и на выполнение любой программы. Кроме того, такой пользователь име­ет возможность полного контроля над системой. Он может остановить её и даже разрушить.

Еще одним важным отличием суперпользователя от обычного пользователя ОС UNIX является то, что на суперпользователя не распространяются ограничения на используемые ресурсы. Для обычных пользователей устанавливаются такие ограничения, как максимальный размер файла, максимальное число сегментов разделяемой памяти, максимально допустимое пространство на диске и т. д. Суперпользователь может изменять эти ограничения для других пользователей, но на него они не действуют.

Команды и командный интерпретатор

Оболочкой (shell) в системе UNIX называют механизм взаимодействия между пользователями и системой. По сути дела, это интерпретатор команд, который считывает набираемые пользователем строки и запускает выполнение запрошен­ных системных функций. Полный командный язык, интерпретируемый оболоч­кой, богат по возможностям и достаточно сложен, однако большинство команд просты в использовании и запомнить их не составляет труда.

Командная строка состоит из имени команды (то есть имени выполняемого фай­ла), за которым следует список аргументов, разделённых пробелами. Оболочка разбивает командную строку на компоненты. Указанный в команде файл загружается, и ему обеспечивается доступ к заданным в команде аргументам.

Любой командный язык семейства shell фактически состоит из трёх частей:

¨ служебных конструкций, позволяющих манипулировать с текстовыми строками и строить сложные команды на основе простых команд;

¨ встроенных команд, выполняемых непосредственно интерпретатором команд­ного языка;

¨ команд, представляемых отдельными выполняемыми файлами.

В свою очередь, набор команд последнего вида включает стандартные команды (системные утилиты, такие как vi, cc и т. д.) и команды, созданные пользователями системы. Для того чтобы выполняемый файл, разработанный пользовате­лем ОС UNIX, можно было запускать как команду shell, достаточно определить в одном из исходных файлов функцию с именем main (имя main должно быть глобальным, то есть перед ним не должно указываться ключевое слово static). Если употребить в качестве имени команды имя такого выполняемого файла, команд­ный интерпретатор создаст новый процесс и запустит в нём указанную выпол­няемую программу, начиная с вызова функции main.

Тело функции main, вообще говоря, может быть произвольным (для интерпрета­тора существенно только наличие входной точки в программу с именем main), но для того, чтобы создать команду, которой можно задавать параметры, нужно придерживаться некоторых стандартных правил. В этом случае каждая функция main должна определяться с двумя параметрами – argc и argv. После вызова ко­манды параметру argc будет соответствовать число символьных строк, указан­ных в качестве аргументов вызова команды, а argv – массив указателей на пе­ременные, содержащие эти строки. При этом имя самой команды составляет первую строку аргументов (то есть после вызова значение argc всегда больше или равно 1). Код функции main должен проанализировать допустимость задан­ного значения argc и соответствующим образом обработать заданные текстовые строки.

Например, следующий текст на языке С может быть использован для создания команды, которая выводит на экран текстовую строку, заданную в качестве её аргумента:

#include < stdio.h>

main(argc, argv)

{

int argc;

char* argv[ ];

if(argc! =2)

{

printf(“usage: %s your-text\n”, argv[0]);

exit;

}

printf(“%s\n”, argv[1]);

}

Процессы

Процесс в ОС UNIX понимается в классическом смысле этого термина, то есть как программа, выполняемая в собственном виртуальном адресном пространст­ве. Когда пользователь входит в систему, автоматически создается процесс, в ко­тором выполняется программа командного интерпретатора. Если командному интерпретатору встречается команда, соответствующая выполняемому файлу, то он создает новый процесс и запускает в нём соответствующую программу, начи­ная с функции main. Эта запущенная программа, в свою очередь, может создать процесс и запустить в нём другую программу (она тоже должна содержать функ­цию main) и т. д.

Для образования нового процесса и запуска в нём программы используются два системных вызова API – fork( ) и ехес(имя_выполняемого_файла). Системный вызов fork приводит к созданию нового адресного пространства, состояние которого абсолютно идентично состоянию адресного пространства основного процесса (то есть в нём содержатся те же программы и данные). Для дочернего процесса заво­дятся копии всех сегментов данных.

Другими словами, сразу после выполнения системного вызова fork основной (родительский) и порожденный процессы являются абсолютными близнецами;

управление и в том и в другом находится в точке, непосредственно следующей за вызовом fork. Чтобы программа могла разобраться, в каком процессе она те­перь работает – в основном или порождённом, функция fork возвращает разные значения: 0 в порождённом процессе и целое положительное число (идентифи­катор порождённого процесса – так называемый PID) в основном процессе.

Теперь, если мы хотим запустить новую программу в порождённом процессе, нужно обратиться к системному вызову ехес, указав в качестве аргументов вызо­ва имя файла, содержащего новую выполняемую программу, и, возможно, одну или несколько текстовых строк, которые будут переданы в качестве аргументов функции main новой программы. Выполнение системного вызова ехес приводит к тому, что в адресное пространство порожденного процесса загружается но­вая выполняемая программа и запускается с адреса, соответствующего входу в функцию main. Другими словами, это приводит к замене текущего программно­го сегмента и текущего сегмента данных, которые были унаследованы при вы­полнении вызова fork, на новые соответствующие сегменты, заданные в файле. Прежние сегменты теряются. Это эффективный метод смены выполняемой про­цессом программы, но не самого процесса. Файлы, уже открытые до выполнения примитива ехес, остаются открытыми после его выполнения.

В следующем примере пользовательская программа, вызываемая как команда shell, выполняет в отдельном процессе стандартную команду shell ls, которая выдаёт на экран содержимое текущего каталога файлов.

main( )

{

if (fork ( )==(0) wait(0); /* родительский процесс */

else execl('ls", " Is", 0); /* порождённый процесс */

}

Таким образом, с практической точки зрения процесс в UNIX является объектом, создаваемым в результате выполнения функции fork( ). Каждый процесс, за исключением начального (нулевого), порождается в результате запуска дру­гим процессом операции fork( ). Каждый процесс имеет одного родителя, но мо­жет породить много процессов. Начальный (нулевой) процесс является особенным процессом, который создается в результате загрузки системы. После порожде­ния нового процесса с идентификатором 1 нулевой процесс становится процес­сом подкачки и реализует механизм виртуальной памяти. Процесс с идентифика­тором 1, известный под именем init, является предком любого другого процесса в системе и связан с каждым процессом особым образом.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-05-29; Просмотров: 692; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.013 с.)
Главная | Случайная страница | Обратная связь