Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
SP_term_work.doc
Скачиваний:
1
Добавлен:
17.11.2019
Размер:
251.9 Кб
Скачать

Рекомендации по написанию командных интерпретаторов для ос unix

1. Структура программы

Интерпретатор команд может работать по следующему упрощенному алгоритму:

1) Анализ командной строки и переменных среды, инициализация

внутренних структур данных;

2) Установка параметров терминала и реакции на сигналы;

3) Вывод приглашения и ожидание ввода пользователя;

4) Анализ командной строки, выполнение всех возможных подстановок;

5) Выполнение встроенной или внешней команды; если введена команда

завершения (exit, logout или Ctrl+D), то закончить работу;

6) Переход к шагу 3.

Так как shell представляет собой довольно крупную программу, то рекомендуется

различные его части оформлять в виде отдельных файлов. Такой подход упростит

поиск обьектов в программе и ускорит процесс перекомпиляции при внесении

локальных изменений.

2. Работа с переменными окружения

Shell, как и любая программа, может получить среду выполнения от процесса-

родителя с помощью 3-го параметра функции main:

int main(int argc, char **argv, char **envp).

Переменная envp указывает на массив строк вида ИМЯ=ЗНАЧЕНИЕ, этот массив можно

анализировать, модифицировать и передавать программам-потомкам с помощью

execle() или execve().

Учтите, что третий параметр main() представляет собой адрес массива указателей

на область хранения переменных среды процесса, эта область наследуется автоматически

при выполнении вызовов типа execl() и execv(). Поэтому, для модификации переменных

необходимо сформировать новый массив строк, и если Вы не передаете среду

запускаемым программам явно (через exec), то новый массив указателей на строки

нужно переписать по адресу envp. По умолчанию cистема осуществляет передачу среды

по наследству путем копирования строк, на которые указывает массив envp.

Исходя из вышесказанного, изменение 1-й переменной среды можно произвести так:

strcpy(envp[1],"USERNAME=scribble"); // неправильно, можно затереть другие

// переменные;

envp[1] = "USERNAME=ralf"; // корректно, так как сама строка лежит в

// сегменте данных.

Если Вы не хотите управлять средой непосредственно, то за Вас это может

сделать система. Системные вызовы getenv(), putenv(), setenv(), unsetenv()

работают с отдельными переменными среды процесса.

3. Установка реакции на сигналы

Сигналы предназначены для оповещения процессов о различных событиях а также

для управления процессами (См. приложение 1). Как сам shell, так и

запускаемые из него программы, должны реагировать определенным образом на

отдельные сигналы. Реакцию процесса на сигналы SIGKILL и SIGSTOP переопределить

нельзя, а на остальные - можно. Но не рекомендуется изменять реакцию на сигналы

типа SIGSEGV или ему подобные, генерирующие при невосстановимых ошибках посмертный

дамп памяти процесса. Возможны различные варианты реакции на сигнал:

1) реакция по умолчанию (например, завершение процесса);

2) игнорирование сигнала;

3) перехват (установка собственного обработчика).

Любой сигнал, кроме SIGKILL и SIGSTOP, может быть блокирован с помощью вызова

sigprocmask(), при этом процесс просто перестает получать сигналы такого типа.

Реакция на сигнал по умолчанию может восстанавливаться при каждом запуске

функции-обработчика - это стандартное поведение системы при использовании

вызова signal(). Включить или выключить восстановление реакции на сигнал по

умолчанию можно параметрами вызова sigaction() - этот вызов может использоваться

вместо signal(). Практически, signal() является упрощенным интерфейсом для

sigaction().

Поведение процесса при получении сигнала внутри обработчика зависит от типа

полученного сигнала, способа установки обработчика и от особенностей реализации

системы. Обычно, если во время обработки сигнала приходит сигнал такого же типа,

его обработка блокируется до выхода из текущего обработчика.

Если во время обработки сигнала приходит один или несколько идентичных (тот же

номер сигнала и PID отправителя), то такие сигналы теряются.

Чтобы не терять важные для работы сигналы нужно разрешить обработку этих сигналов

внутри функции-обработчика. При этом необходимо следить за целостностью глобальных

структур данных, которые модифицируются реентерабельным обработчиком.

Пример: Манипуляции с обработкой сигналов (протестирован под Linux 6.2).

#include <signal.h>

//глобальные переменные

sigset_t cldset; //сигнальная маска

struct sigaction act; //структура для вызова sigaction()

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]