У нас есть две системы RHEL 6, в которых работают идентичные версии ядра и glibc (glibc – 2.12–1.90.el6_3.6). Согласно стандарту POSIX и справочным страницам Linux, если ядро определяет, что исполняемый файл не в исполняемом формате, таком как ELF, и у него нет шебанга (#!) line, функции execl , execlp , execle , execv , execvp и execvpe (но не execve) будут пытаться выполнить этот файл с помощью оболочки POSIX, которая в Linux называется /bin/sh .
Однако в одной из систем выполнение сценария оболочки, первая строка которого : использование функции execvp завершается ошибкой, в то время как на другой машине сценарий выполняется с использованием /bin/sh , как и ожидалось. В частности, мы используем эти тестовые программы; /tmp/test_script сделан исполняемым:
хс:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
extern char **environ;
int main () {
char *argv[] = { "/tmp/test_script", NULL };
char *progname = argv[0];
if (execvp(progname, argv) == -1) {
perror("execvp");
return -1;
}
}
/ TMP / test_script:
: echo "Test script called" exit 0
Мы искали в исходной RPM установленную версию glibc, и она определенно реализует желаемое поведение (execvp - тривиальная оболочка вокруг execvpe):
POSIX /execvpe.c:
if (strchr(file, '/') != NULL)
{
/* Don't search when it contains a slash. */
__execve(file, argv, envp);
if (errno == ENOEXEC)
{
/* Count the arguments. */
int argc = 0;
while (argv[argc++])
;
size_t len = (argc + 1) * sizeof(char *);
char **script_argv;
void *ptr = NULL;
if (__libc_use_alloca(len))
script_argv = alloca(len);
else
script_argv = ptr = malloc(len);
if (script_argv != NULL)
{
scripts_argv(file, argv, argc, script_argv);
__execve(script_argv[0], script_argv, envp);
free(ptr);
}
}
}
else
︙
Здесь scripts_argv - это простая функция, которая добавляет /bin/sh в список аргументов, а __execve идентична execve , доступному для пространства пользователя через glibc.
Кто-нибудь еще сталкивался с этой проблемой в Linux? Поведение корректно в любой другой системе, на которой я его пробовал.
