У нас есть две системы 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? Поведение корректно в любой другой системе, на которой я его пробовал.