Скачиваний:
56
Добавлен:
08.01.2014
Размер:
2.6 Mб
Скачать

5.3. Запуск новых программ при помощи вызова ехес

5.3.1. Семейство вызовов ехес

Если бы вызов fork был единственным доступным для программиста примитивом создания процессов, то система UNIX была бы довольно скучной, так как в ней можно было бы создавать копии только одной программы. К счастью, для смены исполняемой программы можно использовать функции семейства ехес. На рис. 5.2 показано дерево семейства функций ехес. Основное отличие между разными функциями в семействе состоит в способе передачи параметров. Как видно из рисунка, в конечном итоге все эти функции выполняют один системный вызов execve.

Описание

uses stdio;

(* Для семейства вызовов linuxexecl аргументы должны быть списком,

заканчивающимся NULL *)

function linuxexecl(path:pchar;arg0:pchar;argv:array of const):integer;

function linuxexeclp(fname:pchar;arg0:pchar;argv:array of const):integer;

(* Вызову execl нужно передать полный путь к файлу программы *)

Procedure Execl(Path:pathstr);

(* Вызову execle нужно передать полный путь к файлу программы

и массив указателей на строки окружения *)

Procedure Execle(Path:pathstr; Envp:ppchar);

(* Вызову ехесlp нужно только имя файла программы *)

Procedure Execlp(Path:pathstr);

(* Семейству вызовов execv нужно передать массив аргументов *)

(* Вызову execv нужно передать полный путь к файлу программы *)

Procedure Execv(Path:pathstr;argv:ppchar);

(* Вызову execvp нужно только имя файла программы *)

Procedure Execvp(Path:pathstr;argv:ppchar);

(* Вызову execve нужно передать полный путь к файлу программы

и массив указателей на строки окружения *)

Procedure Execve(Path:pchar;argv:ppchar;envp:ppchar);

Procedure Execve(Path:pathstr;argv,envp:ppchar);

execl

execle

execlp

execv

execvp

execve

Рис. 5.2. Дерево семейства вызовов ехес

Все множество системных вызовов ехес выполняет одну и ту же функцию: они преобразуют вызывающий процесс, загружая новую программу в его пространство памяти. Если вызов ехес завершился успешно, то вызывающая программ полностью замещается новой программой, которая запускается с начала. Результат вызова можно рассматривать как запуск нового процесса, который при этом сохраняет идентификатор вызывающего процесса и по умолчанию наследует файловые дескрипторы (см. пункт 5.5.2).

Важно отметить, что вызов ехес не создает новый подпроцесс, который выполняется одновременно с вызывающим, а вместо этого новая программа загружается на место старой. Поэтому, в отличие от вызова fork, успешный вызов ехеc не возвращает значения.

Для простоты осветим только один из вызовов ехес, а именно linuxexecl.

Все аргументы функции linuxexecl являются указателями строк. Первый из них, аргумент path, задает имя файла, содержащего программу, которая будет запущена на выполнение; для вызова linuxexecl это должен быть полный путь к программе, абсолютный или относительный. Сам файл должен содержать программу или последовательность команд оболочки и быть доступным для выполнения. Система определяет, содержит ли файл программу, просматривая его первые байты (обычно первые два байта). Если они содержат специальное значение, называемое магическим числом (magic number), то система рассматривает файл как программу. Второй аргумент, arg0, является, по соглашению, именем программы или команды, из которого исключен путь к ней. Этот аргумент и оставшееся переменное число аргументов (массив args) доступны в вызываемой программе, аналогично аргументам командной строки при запуске программы из оболочки. В действительности командный интерпретатор сам вызывает команды, используя один из вызовов ехес совместно с вызовом fork. Так как список аргументов имеет произвольную длину, он должен заканчиваться нулевым указателем для обозначения конца списка.

Короткий пример ценнее тысячи слов – следующая программа использует вызов execl для запуска программы вывода содержимого каталога ls:

(* Программа runls - использование "execl" для запуска ls *)

uses linux,stdio;

begin

writeln('Запуск программы ls');

execl('/bin/ls -l');

(* Если execl возвращает значение, то вызов был неудачным *)

perror ('Вызов execl не смог запустить программу ls');

halt(1);

end.

Работа этой демонстрационной программы показана на рис. 5.3. Часть Допоказывает процесс непосредственно перед вызовомexecl. ЧастьПослепоказывает измененный процесс после вызоваexecl, который при этом выполняет программуls. Программный счетчикPCуказывает на первую строку программыls, показывая, что вызовexeclзапускает программу с начала.

writeln(...);

← PC

execl('/bin/ls -l');

runls

exec

До

После

(* 1-ая строка ls*)

← PC

Команда ls

Рис. 5.3. Вызов exec

Обратите внимание, что в примере за вызовом execl следует безусловный вызов библиотечной процедуры perror. Это отражает то, что успешный вызов функции execl (и других родственных функций) стирает вызывающую программу. Если вызывающая программа сохраняет работоспособность и происходит возврат из вызова execl, значит, произошла ошибка. Поэтому возвращаемое значение execl и родственных функций всегда равно -1.

Соседние файлы в папке Полищук, Семериков. Системное программирование в UNIX средствами Free Pascal