execveat(2) выполняет программу, определяемую относительно файлового

ОБЗОР

#include <unistd.h>

int execveat(int dirfd, const char *pathname,
char *const argv[], char *const envp[],
int flags);

ОПИСАНИЕ

Системный вызов execveat() выполняет программу, на которую ссылается комбинация dirfd и pathname. Он работает также как системный вызов execve(2), за исключением случаев, описанных в данной справочной странице.

Если в pathname задан относительный путь, то он считается относительно каталога, на который ссылается файловый дескриптор dirfd (а не относительно текущего рабочего каталога вызывающего процесса, как это делается в execve(2)).

Если в pathname задан относительный путь и dirfd равно специальному значению AT_FDCWD, то pathname рассматривается относительно текущего рабочего каталога вызывающего процесса (как execve(2)).

Если в pathname задан абсолютный путь, то dirfd игнорируется.

Если pathname — пустая строка и указан флаг AT_EMPTY_PATH, то файловым дескриптором dirfd задаётся выполняемый файл (т. е., dirfd ссылается на исполняемый файл, а не на каталог).

Аргумент flags является битовой маской, которая может включать ноль или более следующих флагов:

AT_EMPTY_PATH
Если значение pathname равно пустой строке, то вызов выполняет действие с файлом, на который ссылается dirfd (может быть получен с помощью open(2) с флагом O_PATH).
AT_SYMLINK_NOFOLLOW
Если файл задаётся dirfd и pathname — символическая ссылка (не NULL), то вызов завершается с ошибкой ELOOP.

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ

При успешном выполнении execveat() не возвращает управление. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.

ОШИБКИ

В execveat() могут возникнуть те же ошибки, что и в execve(). Также, в execveat() могут возникнуть следующие ошибки:
EBADF
dirfd не является правильным файловым дескриптором.
EINVAL
Указано неверное значение в flags.
ELOOP
Значение flags содержит AT_SYMLINK_NOFOLLOW и файл задаётся dirfd, а pathname — символическая ссылка (не NULL).
ENOENT
Программа задаётся dirfd и по pathname требуется использовать интерпретирующую программу (то есть сценарий, начинающийся с «#!»), но файловый дескриптор dirfd открыт с флагом O_CLOEXEC, что приводит к недоступности файла программы запускаемому интерпретатору. Смотрите ДЕФЕКТЫ.
ENOTDIR
Значение pathname содержит относительный путь и dirfd содержит файловый дескриптор, указывающий на файл, а не на каталог.

ВЕРСИИ

Вызов execveat() был добавлен в ядро Linux версии 3.19; поддержки в библиотеке GNU C пока нет.

СООТВЕТСТВИЕ СТАНДАРТАМ

Системный вызов execveat() есть только в Linux.

ЗАМЕЧАНИЯ

В дополнении к причинам, описанным в openat(2), системному вызову execveat() также требуется разрешить fexecve(3) для реализации в системах, у которых не смонтированной файловой системы /proc.

При запросе запуска файла сценария, значение argv[0], передаваемое в интерпретатор сценарий, является строкой в виде /dev/fd/N или /dev/fd/N/P, где N — номер файлового дескриптора, передаваемого через аргумент dirfd. Строка в первом формате встречается, когда указан AT_EMPTY_PATH. Строка во втором формате встречается, когда сценарий задаётся сразу через dirfd и pathname; в этом случае P — это значение, указанное в pathname.

По причинам, описанным в fexecve(3), естественным подходом является использование execveat(2) с установленным флагом закрытия-при-выполнении у dirfd. (но смотрите ДЕФЕКТЫ).

ДЕФЕКТЫ

Ошибка ENOENT, описанная выше, означает, что невозможно установить флаг закрытия-при-выполнении у файлового дескриптора, переданного вызову в виде:


    execveat(fd, "", argv, envp, AT_EMPTY_PATH);

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