ИМЯ execve - выполнить программу
ОБЗОР #include <unistd.h>
int execve(const char *filename, char *const argv[], char *const envp[]);
ОПИСАНИЕ execve() выполняет программу, задаваемую аргументом filename. В filename должно быть указано имя двоичного исполняемого файла или сценарий, начинающийся со строки вида:
#! интерпретатор [необязательные параметры]
Подробней о сценариях написано далее в "Интерпретируемые сценарии".
argv — это массив строковых параметров, передаваемых новой программе. По соглашению, в первой строке (т. е., argv[0]) должно содержаться имя файла, относящееся к запускаемой программе. envp — это массив строк в формате ключ=значение, которые передаются новой программе в качестве окружения (environment). Оба массива argv и envp завершаются указателем null.
К массиву параметров и окружению можно обратиться из вызываемой программой главной функции, если она определена как:
int main(int argc, char *argv[], char *envp[])
Однако заметим, что использование третьего аргумента главной функции не определено в POSIX.1; согласно POSIX.1, окружение должно быть доступно через внешнюю переменную environ(7).
При успешном выполнении execve() управление не возвращается, а код, инициализированные данные, неинициализированные данные (bss) и стек вызвавшего процесса перезаписываются содержимым загруженной программы.
Если текущая программа выполнялась под управлением ptrace, то после успешного вызова execve() ей посылается сигнал SIGTRAP.
Если у файла программы, указанного в filename, установлен бит set-user-ID и файловая система, в которой он хранится, не смонтирована с параметром nosuid (флаг MS_NOSUID у mount(2)), и вызывающий процесс не выполняется под управлением ptrace, то фактический идентификатор пользователя вызывающего процесса меняется на идентификатор владельца файла программы. Точно также, если на файле программы установлен бит set-group-ID, то фактический идентификатор группы вызывающего процесса становится равным группе, которой принадлежит файл программы.
Фактический идентификатор пользователя процесса копируется в сохранённый идентификатор пользователя (set-user-ID), также фактический идентификатор группы копируется в сохранённый идентификатор группы (set-group-ID). Это копирование выполняется после изменения любого фактического идентификатора, которое происходит из-за выставленных бит режима set-user-ID и set-group-ID.
Реальные UID и GID процесса, а также иго дополнительные ID групп не изменяются при вызове execve(2).
При вызове execve() сохраняются все свойства процесса, за исключением:
* Значения обработчиков всех захватываемых сигналов сбрасываются в значения по умолчанию (signal(7)).
* Любой альтернативный стек сигнала не сохраняется (sigaltstack(2)).
* Проецирование памяти не сохраняется (mmap(2)).
* Подключённые общие сегменты памяти System V отключаются (shmat(2)).
* Области общей памяти POSIX становятся неспроецированными (shm_open(3)).
* Открытые дескрипторы в очереди сообщений POSIX закрываются (mq_overview(7)).
* Все открытые именные семафоры POSIX закрываются (sem_overview(7)).
* Таймеры POSIX не сохраняются (timer_create(2)).
* Все открытые потоки каталогов (directory streams) закрываются (opendir(3)).
* Блокировки памяти не сохраняются (mlock(2), mlockall(2)).
* Обработчики завершения работы (exit handlers) не сохраняются (atexit(3), on_exit(3)).
* Окружения плавающей точки сбрасываются в настройки по умолчанию (fenv(3)).
В POSIX.1 определён список сохраняемых свойств процесса. Следующие свойства процесса, имеющиеся только в Linux, также не сохраняются при execve():
* Устанавливается флаг PR_SET_DUMPABLE (prctl(2)), если выполняемая программа не имеет установленных бит set-user-ID или set-group-ID; в противном случае он очищается.
* Флаг PR_SET_KEEPCAPS (prctl(2)) очищается.
* (Начиная с Linux 2.4.36 / 2.6.23) Если выполняется программа с установленным битом set-user-ID или set-group-ID, то сигнал о смерти родителя, установленный prctl(2) с флагом PR_SET_PDEATHSIG, очищается.
* Имя процесса, установленное через prctl(2) PR_SET_NAME (и отображаемое ps -o comm), изменяется на имя нового исполняемого файла.
* Флаг SECBIT_KEEP_CAPS securebits очищается. Смотрите capabilities(7).
* Сигнал завершения (termination signal) устанавливается в SIGCHLD (clone(2)).
* Таблица файловых дескрипторов не является общей, отменяется действие флага CLONE_FILES у clone(2).
Также стоит учитывать следующее:
* Все нити (threads), отличные от вызывающей, уничтожаются execve(). Мьютексы, условные переменные и другие объекты pthreads не сохраняются.
(aio_read(3), aio_write(3)).
* Как происходит обработка мандатов (capabilities) при вызове execve(), см. capabilities(7).
* По умолчанию, после execve() файловые дескрипторы остаются открытыми. Файловые дескрипторы, помеченные как close-on-exec (закрывать при запуске), закрываются; смотрите описание FD_CLOEXEC в fcntl(2) (если файловый дескриптор закрыт, это приводит к освобождению всех имеющихся блокировок, полученных на соответствующий файл данным процессом. Подробней смотрите fcntl(2)). В POSIX.1 сказано, что если бы файловые дескрипторы 0, 1 и 2 были закрыты после успешного вызова execve(), и процесс получил бы привилегии из-за установленных битов режима set-user_ID или set-group_ID на исполняемом файле, то система смогла бы открыть произвольный файл для каждого из этих дескрипторов. Считается, что переносимая программа, с привилегиями или без, не может рассчитывать, что эти три файловых дескриптора будут оставаться закрытыми после execve().
Интерпретируемые сценарии Интерпретируемый сценарий — это текстовый файл, у которого установлен бит выполнения и первая строка имеет вид:
#! интерпретатор [необязательные параметры]
В поле интерпретатор должно быть указано имя файла запуска. Если в аргументе filename для execve() указан интерпретируемый сценарий, то интерпретатор будет вызван со следующими параметрами:
интерпретатор [необязательный параметр] имя файла параметр...
где параметр... — последовательность слов, указываемых аргументом argv в execve() начиная с argv[1].
В целях переносимости, необязательный параметр должен быть или пустым, или задаваться одним словом (т.е., не должен содержать пробельных символов); см. ЗАМЕЧАНИЯ далее.
Начиная с Linux 2.6.28 ядро позволяет интерпретатору сценария самому быть сценарием. Это разрешение рекурсивно (до четырёх раз), поэтому сценарий может быть сценарием, который интерпретируется сценарием и т. д.
Ограничения на размер параметров и окружения Большинство реализаций UNIX накладывает некоторые ограничения на полный размер параметра командной строки (argv) и окружения (envp), которые можно передать новой программе. POSIX.1 позволяет реализации объявить это ограничение через константу ARG_MAX (определённую в <limits.h> или сделать её доступной во время выполнения через вызов sysconf(_SC_ARG_MAX)).
В ядре Linux до версии 2.6.23 размер памяти, используемый для хранения окружения и строк параметров, был ограничен 32 страницами (определялся ядерной константой MAX_ARG_PAGES). На архитектурах с 4-КиБ размером страницы это давало максимальный размер в 128 КиБ.
Начиная с ядра версии 2.6.23, большинство архитектур поддерживают предельный размер, высчитываемый от мягкого ограничения ресурса RLIMIT_STACK (см. getrlimit(2)), который действует во время вызова execve(). (Исключение составляют архитектуры без механизма управления памятью: в них ограничение рассчитывается как и до версии 2.6.23.) Это изменение позволяет программам иметь больший список
ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ При успешном выполнении execve() не возвращает управление. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
ОШИБКИ E2BIG Слишком большое общее количество байт для окружения (envp) и списка параметров (argv).
EACCES В одном из каталогов префикса filename или интерпретатора не разрешён поиск. (см. также path_resolution(7))
EACCES Файл или интерпретатор не являются обычным файлом.
EACCES Не установлен бит выполнения на файле или сценарии или интерпретаторе ELF.
EACCES Файловая система смонтирована с noexec.
EAGAIN (начиная с Linux 3.1) Из-за изменения реального UID одним из вызовов set*uid() ранее, вызывающий всё ещё превышает ограничитель ресурса RLIMIT_NPROC (смотрите setrlimit(2)). Подробное объяснение этой ошибки смотрите в ЗАМЕЧАНИЯХ.
EFAULT Значение filename или один из указателей в векторах argv или envp указывает за пределы доступного адресного пространства.
EINVAL Исполняемый ELF-файл содержит более одного сегмента PT_INTERP (т.е., в нём указано более одного интерпретатора).
EIO Произошла ошибка ввода-вывода.
EISDIR Интерпретатор ELF является каталогом.
ELIBBAD Не распознан формат интерпретатора ELF.
ELOOP Во время определения filename, имени сценария или интерпретатора ELF встретилось слишком много символьных ссылок.
ELOOP Достигнут предел количества рекурсий при интерпретации сценария (смотрите «Интерпретируемые сценарии» выше). До Linux 3.8 для этого случая возвращалась ошибка ENOEXEC.
EMFILE Было достигнуто ограничение по количеству открытых файловых дескрипторов на процесс.
ENAMETOOLONG Слишком
|