
учебник
.pdf
Рис. 2.4 Установка пакетов из репозиториев
Обратите внимание, aptitude предлагает вам в квадратных скобочках три возможных варианта ответа на поставленный вопрос:
[Y/n/?]Y означает Yes, то есть согласие, n – это No, то есть отказ, а ? – это просьба вывести справку. Вам нужно ввести символ, соответствующий вашему выбору и нажать Enter. Однако часто есть вариант по умолчанию, выделенный в списке большой буквой, и если вам нужен именно он, то вы можете ничего не вводить, просто нажать
Enter.
Аналогично установке, удалить пакеты можно одной из двух команд:
sudo aptitude remove имя_пакета1 [имя_пакета2 ...] sudo aptitude purge имя_пакета1 [имя_пакета2 ...]
Первая удаляет только файлы пакета, оставляя пользовательские настройки нетронутыми, вторая же удаляет пакет полностью. Посмотреть описание конкретного пакета можно командой
aptitude show имя_пакета
Произвести поиск нужного пакета по доступным источникам приложений можно командой
41

aptitude search фраза
По умолчанию поиск производится по именам пакетов, для поиска по описаниям надо перед искомой фразой добавить символ ~d:
aptitude search ~d фраза
aptitude имеет мощный графический интерфейс, попасть в него можно набрав в терминале просто aptitude. Вот как это выглядит:
Несмотря на неприглядный вид работать с этим очень удобно. Обычно в разнообразных инструкциях для установки пакетов предлагается как раз использовать команду
sudo aptitude install имя_пакета
Это ни в коей мере не значит, что обязательно надо исполнять эту команду. Вы спокойно можете поставить указанные пакеты через тот же Synaptic. Просто авторы инструкций обычно экономят свое время на объяснении, куда и как надо нажимать в Synaptic, давая вместо всего этого одну маленькую команду. Но в конечном итоге aptitude и Synaptic выполняют одни и те же действия.
Рис. 2.5 Интерфейс утилиты aptitude
42
Утилита apt-get
В инструкциях гораздо чаще вместо aptitude используется apt-get. apt-get – это стандартная утилита управления пакетами, используется она ровно так же, как и aptitude, только у нее нет графического интерфейса и поиска. То есть во всех командах с install, remove, purge можно вместо aptitude писать apt-get.
Порядок выполнения лабораторной работы
1.Войдите как суперпользователь. Создайте нового пользователя: имя, группа, права, название домашнего каталога (задаются).
2.Установите программу:
через менеджер пакетов,
с использованием командной строки.
установка из исходных кодов.
3.Создать архив разными способами.
4.Создать сжатый архив.
5.Распаковать архив.
Контрольные вопросы
1.Дайте определение функциям администратора и суперпользователя.
2.Опишите процесс регистрации нового пользователя.
3.Опишите процесс установки программ.
4.Опишите выполнение архивирования и использование архиваторов.
5.Копирование файлов на стример.
6.Команда CPIO (Copy In/Out).
7.Архивация со сжатием.
8.Менеджер пакетов Synaptic.
9.Консольные инструменты управления пакетами.
43
Лабораторная работа 3
ПРОЦЕССЫ В ОПЕРАЦИОННОЙ СИСТЕМЕ UNIX
Цели и задачи
Знакомство с процессной организацией UNIX-подобных систем. Изучение информационных команд отслеживания информации о процессах. Изучение различных типов процессов. Изучение информации о первичном процессе init и уровнях загрузки системы. Создание программы на языке Си, реализующей порождение и замещение процессов с использованием системных вызовов UNIX, запуск команд UNIX из пользовательской программы.
3.1 Понятие процесса UNIX. Его контекст. Многозадачность
Процессы в Linux, как и файлы, являются аксиоматическими понятиями. Обычно процесс отождествляют с запущенной программой. Будем считать, что процесс - это рабочая единица системы, которая что-то выполняет. Многозадачность - это возможность одновременного сосуществования нескольких процессов в одной системе.
Linux - многозадачная операционная система. Это означает, что процессы в ней работают одновременно. Естественно, это условная формулировка. Ядро Linux постоянно переключает процессы, то есть время от времени дает каждому из них скольконибудь процессорного времени. Переключение происходит довольно быстро, поэтому нам кажется, что процессы работают одновременно.
Одни процессы могут порождать другие процессы, образуя древовидную структуру. Порождающие процессы называются родителями или родительскими процессами, а порожденные - потомками или дочерними процессами. На вершине этого «дерева» находится процесс init, который порождается автоматически ядром в процессе загрузки системы.
Получение информации о процессах в системе
Для получения информации о процессах в системе наиболее часто используются утилиты ps и top. В Linux вся информация о динамике выполнения системы отражается в каталоге /proc, утилиты
44

ps и top собирают данные о запущенных процессах на основании информации, находящейся в этом каталоге.
Контекст процесса складывается из пользовательского контекста и контекста ядра, как изображено на рисунке 3.1.
Рис. 3.1. Контекст процесса в UNIX
Под пользовательским контекстом процесса понимают код и данные, расположенные в адресном пространстве процесса. Все данные подразделяются:
на инициализируемые неизменяемые данные (например, константы);
инициализируемые изменяемые данные (все переменные, начальные значения которых присваиваются на этапе компиляции);
не инициализируемые изменяемые данные (все статические переменные, которым не присвоены начальные значения на этапе компиляции);
стек пользователя;
данные, расположенные в динамически выделяемой памяти
45
(например, с помощью стандартных библиотечных C функций malloc(), calloc(), realloc()).
Исполняемый код и инициализируемые данные составляют содержимое файла программы, который исполняется в контексте процесса. Пользовательский стек применяется при работе процесса в пользовательском режиме (user-mode).
Под понятием «контекст ядра» объединяются системный контекст и регистровый контекст. Мы будем выделять в контексте ядра стек ядра, который используется при работе процесса в режиме ядра (kernel mode), и данные ядра, хранящиеся в структурах, являющихся аналогом блока управления процессом — PCB. Состав данных ядра будет уточняться на последующих семинарах. На этом занятии нам достаточно знать, что в данные ядра входят: идентификатор пользователя — UID, групповой идентификатор пользователя — GID, идентификатор процесса — PID, идентификатор родительского процесса — PPID.
3.2 Идентификация процесса. Иерархия процессов
Каждый процесс в операционной системе получает уникальный идентификационный номер – PID (process identificator). При создании нового процесса операционная система пытается присвоить ему свободный номер больший, чем у процесса, созданного перед ним. Если таких свободных номеров не оказывается (например, мы достигли максимально возможного номера для процесса), то операционная система выбирает минимальный номер из всех свободных номеров. В операционной системе Linux присвоение идентификационных номеров процессов начинается с номера 0, который получает процесс kernel при старте операционной системы. Этот номер впоследствии не может быть присвоен никакому другому процессу. Максимально возможное значение для номера процесса в Linux на базе 32-разрядных процессоров Intel составляет 231-1.Все процессы системы UNIX, кроме одного, создающегося при старте операционной системы, могут быть порождены только какими-либо другими процессами. Процессы с номерами 1 или 0 могут выступать в качестве прародителя всех остальных процессов в системах, подобных
UNIX.
Таким образом, все процессы в UNIX связаны отношениями процесс-
46
родитель – процесс-потомок и образуют генеалогическое дерево процессов. Для сохранения целостности генеалогического дерева в ситуациях, когда процесс-родитель завершает свою работу до завершения выполнения процесса-потомка, идентификатор родительского процесса в данных ядра процесса-потомка (PPID – parent process identificator) изменяет свое значение на значение 1, соответствующее идентификатору процесса init, время жизни которого определяет время функционирования операционной системы. Тем самым процесс init как бы «усыновляет осиротевшие процессы».
3.3 Состояния процесса. Краткая диаграмма состояний
Модель состояний процессов в операционной системе UNIX представляет собой детализацию модели состояний. Краткая диаграмма состояний процессов в операционной системе UNIX изображена на рисунке 3.2.
Как мы видим, состояние процесса исполнение расщепилось на два состояния: исполнение в режиме ядра и исполнение в режиме пользователя. В состоянии «исполнение в режиме пользователя» процесс выполняет прикладные инструкции пользователя. В состоянии «исполнение в режиме ядра» выполняются инструкции ядра операционной системы в контексте текущего процесса (например, при обработке системного вызова или прерывания). Из состояния «исполнение в режиме пользователя» процесс не может непосредственно перейти в состояния «ожидание», «готовность» и «закончил исполнение». Такие переходы возможны только через промежуточное состояние «исполняется в режиме ядра». Также запрещен прямой переход из состояния «готовность» в состояние «исполнение в режиме пользователя».
47

Рис. 3.2 Сокращенная диаграмма состояний процесса в UNIX
3.4 Понятие системного вызова
В любой операционной системе поддерживается некоторый механизм, который позволяет пользовательским программам обращаться за услугами ядра ОС UNIX, такие средства называются системными вызовами. Смысл системных вызовов состоит в том, что для обращения к функциям ядра ОС используются «специальные команды» процессора, при выполнении которых возникает особого рода внутреннее прерывание процессора, переводящее его в режим ядра (в большинстве современных ОС этот вид прерываний называется trap - ловушка). При обработке таких прерываний ядро ОС распознает, что на самом деле прерывание является запросом к ядру со стороны пользовательской программы на выполнение определенных действий, выбирает параметры обращения и обрабатывает его, после чего выполняет «возврат из прерывания», возобновляя нормальное выполнение пользовательской программы. Понятно, что конкретные механизмы возбуждения внутренних прерываний по инициативе пользовательской программы различаются в разных аппаратных архитектурах. Поскольку ОС UNIX стремится обеспечить среду, в которой пользовательские программы могли бы быть полностью мобильны, потребовался дополнительный уровень, скрывающий особенности конкретного механизма возбуждения внутренних
48
прерываний. Этот механизм обеспечивается так называемой библиотекой системных вызовов.
Для пользователя библиотека системных вызовов представляет собой обычную библиотеку заранее реализованных функций системы программирования языка Си. При программировании на языке Си использование любой функции из библиотеки системных вызовов ничем не отличается от использования любой собственной или библиотечной Си-функции. Однако внутри любой функции конкретной библиотеки системных вызовов содержится код, являющийся, вообще говоря, специфичным для данной аппаратной платформы.Поведение всех программ в системе вытекает из поведения системных вызовов, которыми они пользуются. Сам термин «системный вызов» как раз означает «вызов системы для выполнения действия», т. е. вызов функции в ядре системы. Ядро работает в привилегированном режиме – режим ядра, в котором имеет доступ к системным таблицам, регистрам и портам внешних устройств и диспетчера памяти, к которым обычным программам доступ аппаратно запрещен.
Системные вызовы getuid и getgid. Узнать идентификатор пользователя, запустившего программу на исполнение (UID), и идентификатор группы, к которой он относится (GID), можно с помощью системных вызовов getuid() и getgid(), применив их внутри этой программы.
Прототипы системных вызовов
#include <sys/types.h> #include <unistd.h> uid_t getuid(void); gid_t getgid(void);
Описание системных вызовов:
Системный вызов getuid возвращает идентификатор пользователя для текущего процесса.
Системный вызов getgid возвращает идентификатор группы пользователя для текущего процесса.
Типы данных uid_t и gid_t являются синонимами для одного из целочисленных типов языка Си.
49
Системные вызовы getppid() и getpid(). Данные ядра, находящиеся в контексте ядра процесса, не могут быть прочитаны процессом непосредственно. Для получения информации о них процесс должен совершить соответствующий системный вызов. Значение идентификатора текущего процесса может быть получено с помощью системного вызова getpid(), а значение идентификатора родительского процесса для текущего процесса – с помощью системного вызова getppid(). Системные вызовы не имеют параметров и возвращают идентификатор текущего процесса и идентификатор родительского процесса соответственно.
Прототипы системных вызовов
#include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getppid(void);
Описание системных вызовов
Системный вызов getpid возвращает идентификатор текущего процесса.
Системный вызов getppid возвращает идентификатор процессародителя для текущего процесса. Тип данных pid_t является синонимом для одного из целочисленных типов языка Си.
Пример 3-01 использования getpid() и getppid() для извлечения идентификаторов процессов.
#include<iostream> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <signal.h> #include<cstdlib> Using namespace std; void mpinfo()
{
50