Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учеб.пос.СП.doc
Скачиваний:
36
Добавлен:
31.03.2015
Размер:
1.33 Mб
Скачать
    1. Системный вызов exec

Понять системные вызовы exec и fork без четкого понимания различий между процессом и программой невозможно. Напомним суть различий: процесс – это среда исполнения, которая включает в себя сегмент исполняемого кода, сегменты пользовательских и системных данных, а также набор дополнительных ресурсов, полученных во время исполнения. Программа - это файл, который содержит исполняемый код, сегменты с данными для инициализации и с данными пользователя.

Системный вызов exec повторно инициализирует процесс, подменяя его указанной программой - программа меняется, а процесс остается. Системный вызов fork наоборот запускает новый процесс, который является точной копией существующего, простым копированием сегментов с исполняемым кодом и данными. Вновь созданный процесс продолжает работу с того же места, что и изначальный, таким образом, оба процесса продолжают исполнять один и тот же код.

Системный вызов exec - единственный способ запуска программ в Unix, а системный вызов fork - единственный способ запустить новый процесс. На самом деле, системного вызова с именем exec не существует. Под этим именем подразумевается целое семейство из шести системных вызовов, имена которых можно записать как execAB. A – это один из символов l или v, они определяют, как входные аргументы передаются вызову - в виде списка или в виде массива. B (может отсутствовать) – это либо p, указывающий, что поиск файла программы должен выполняться с помощью переменной PATH, либо e - такому вызову передается специфичная среда окружения. Получается шесть различных системных вызовов: execl, execv, execlp, execvp, execle и execve. Рассмотрим execl:

execl - запускает программу, входные аргументы передаются в виде списка

#include <unistd.h>

int execl (

const char *path, /* полный путь к программе */

const char *arg0, /* первый аргумент – имя файла */

const char *arg1, /* второй аргумент*/

…………………… /* остальные аргументы */

NULL /* пустой указатель, завершающий список */

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

Аргумент path должен содержать полное имя исполняемого файла с программой действующего идентификатора пользователя (например, с правами 755). Исполняемый код процесса будет затерт исполняемым кодом новой программы, сегмент данных также будет затерт сегментом данных новой программы, а стек будет переинициализирован. Исполнение новой программы начнется с самого начала. В случае успеха возврат из execl не предусмотрен, потому что точка возврата будет утеряна. В случае ошибки execl вернет -1. Наиболее частые причины, приводящие к невозможности запустить новую программу, это либо отсутствие файла с программой, либо отсутствие права на ее запуск. Все остальные аргументы вызова собираются в массив указателей на строки, а последним всегда должен стоять пустой указатель, который определяет конец списка входных аргументов. Первый аргумент – это имя файла программы (только само имя, без пути к нему). Новая программа получает доступ к этому списку через уже знакомые нам аргументы функции main() - argc и argv. Среда окружения также передается новой программе и доступна ей через указатель environ или посредством функции getenv.

Поскольку процесс продолжает существовать и сегмент с системными данными практически не изменяется, почти все атрибуты также остаются неизменными, включая идентификатор процесса, идентификатор процесса-предка, идентификатор группы процесса, идентификатор сессии, управляющий терминал, реальные идентификаторы пользователя и группы, текущий и корневой каталоги, приоритет, статистические характеристики времени исполнения в пространстве пользователя и в пространстве ядра и, как правило, дескрипторы открытых файлов. Гораздо проще перечислить основные атрибуты, которые изменяются:

  • если процесс назначал свои обработчики сигналов, то все они сбрасываются в исходное состояние, поскольку функции-обработчики после запуска новой программы станут недоступны;

  • если в новой программе установлены биты set-user-ID или set-group-ID, то действующие идентификаторы пользователя и группы переустанавливаются в соответствии с идентификаторами владельца и группы файла программы. Нет никакого способа вернуть прежние действующие идентификаторы, если они отличаются от реальных;

  • регистрация всех функций, которая была выполнена с помощью atexit(), отменяется, поскольку код этих функций будет затерт;

  • сегменты общей памяти отсоединяются, поскольку точки соединения будут утеряны;

  • именованные семафоры POSIX закрываются. Семафоры System V остаются без изменений.

Если сохранение атрибута или ресурса не имеет смысла, то он или сбрасывается в состояние по умолчанию, или закрывается.

Другие пять вызовов семейства exec предоставляют три дополнительные возможности, недоступные в execl:

  • передать аргументы в виде массива, а не в виде списка. Это совершенно необходимо, когда число аргументов в момент написания программы заранее неизвестно;

  • поиск файла программы с использованием значения переменной окружения PATH, как это делает командная оболочка;

  • передавать указатель на сформированную вручную среду окружения вместо неявной передачи указателя environ.

Ниже приводится краткое описание остальных системных вызовов семейства exec:

execv - запускает программу, аргументы передаются в виде массива

#include <unistd.h>

int execv (

const char *path, /* полный путь к файлу с программой */

char * const argv[ ] /* массив аргументов */

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

execlp - запускает программу, аргументы передаются в виде списка, поиск файла ведется с использованием переменной PATH

#include <unistd.h>

int execlp (

const char *file, /* имя файла с программой */

const char *arg0, /* первый аргумент – имя файла */

const char *arg1, /* второй аргумент*/

…………………… /* остальные аргументы */

NULL /* пустой указатель, завершающий список аргументов*/

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

execvp - запускает программу, аргументы передаются в виде массива, поиск файла ведется с использованием переменной PATH

#include <unistd.h>

int execvp (

const char *file, /* имя файла с программой */

char * const argv[ ] /* массив аргументов */

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

execle - запускает программу, аргументы передаются в виде списка, так же передается среда окружения

#include <unistd.h>

int execle (

const char *path, /* полный путь к файлу с программой */

const char *arg0, /* первый аргумент – имя файла */

const char *arg1, /* второй аргумент*/

…………………… /* остальные аргументы */

NULL /* пустой указатель, завершающий список аргументов*/

char *const envv[ ] /* массив сформированной среды окружения */

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

execve - запускает программу, аргументы передаются в виде списка, так же передается среда окружения

#include <unistd.h>

int ve (

const char *path, /* полный путь к файлу с программой */

char * const argv[ ], /* массив аргументов */

char *const envv[ ] /* массив сформированной среды окружения */

);

/* В случае ошибки возвращает -1 (код ошибки - в переменной errno) */

Используемый аргумент argv абсолютно идентичен аргументу argv, передаваемому функции main. Последним в этом массиве всегда должен стоять NULL. Если аргумент file в вызовах execlp или execvp не содержит символ «/», то выполняется последовательная подстановка имен каталогов из переменной PATH и производится поиск файла с правом на исполнение. Если такой файл найден, и он является исполняемой программой, то она запускается на исполнение. Если нет, то делается предположение о том, что файл является сценарием и вызывается командный интерпретатор, которому передается путь к файлу в первом аргументе.

Например, если file - это команда echo, и в результате поиска был обнаружен файл /bin/echo, то этот файл будет запущен как программа, потому что он содержит команды микропроцессора.