Подтвердить что ты не робот

Как execvp запускает команду?

Я знаю, что execvp может использоваться для выполнения простых команд следующим образом:

char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);

Я хочу знать, что происходит здесь, когда я запускаю execvp. В man-странице говорится: execvp заменяет изображение образа процесса новым. Однако здесь я выполняю команду, а не исполняемый файл.

Чтобы быть конкретным, скажем, есть команда, которая специально требует ввода, например. Кот. Если у меня есть текстовый файл text.txt, который содержит имя файла, ожидаемое для cat, и я перенаправляю stdin к файловому потоку файла, будет вывод execle("cat","cat",NULL) или execvp("cat", arg) (очевидно, где arg хранит "cat" и NULL) приведет к выводу в консоли, как cat /filename? Моя интуиция заключается в том, что я должен прочитать файл и, возможно, проанализировать его для хранения аргументов в arg. Однако я хочу убедиться.

Спасибо заранее!

4b9b3361

Ответ 1

Здесь что происходит в вызове execvp:

  • Ваша реализация libc ищет в PATH, если применимо, файл, который должен быть выполнен. Большинство, если не все, команд в UNIX-подобных системах являются исполняемыми. Что произойдет, если это не так? Попробуй. Посмотрите как glibc делает это.
  • Как правило, если исполняемый файл найден, будет выполнен вызов execve. Части execve могут быть реализованы в libc, или это может быть системный вызов (например, в Linux).
  • Linux готовит программу, выделяя для нее память, открывая ее, планируя ее на выполнение, инициализирует структуры памяти, устанавливает свои аргументы и среду из предоставленных аргументов в вызов execvp, находит обработчик, подходящий для загрузки двоичного кода, и устанавливает текущую задачу (вызывающий execvp) как не выполняемый. Вы можете найти его реализацию здесь.

Все шаги выше соответствуют требованиям, установленным POSIX, которые описаны в соответствующих страницах руководства.

Ответ 2

Относительно ваших вопросов:

В man-странице говорится: execvp заменяет изображение образа процесса с новым. Однако здесь я выполняю команду не исполняемый файл.

Долгое время назад оболочка была очень ограниченной, и почти все команды UNIX были автономными исполняемыми файлами. Теперь, главным образом для целей скорости, некоторые подмножества команд UNIX реализуются внутри самой оболочки, эти команды называются builtins. Вы можете проверить, какая команда реализована в вашей оболочке как встроенная или не с помощью команды type:

λ ~/ type echo
echo is a shell builtin

(Полный список встроенных функций с описаниями можно найти на страницах man для вашей оболочки, например, man bash-builtins или man builtin.)

Но у большинства команд все еще есть свой исполняемый-дубликат:

λ ~/ whereis echo
/bin/echo

Итак, в вашем конкретном случае, когда вы работаете:

char* arg[] = {"ls", "-l", NULL};
execvp(arg[0],arg);

Фактически вы заменяете адресное пространство текущего процесса адресным пространством (скорее всего) /bin/ls.


Моя интуиция заключается в том, что я должен прочитать файл и, возможно, проанализировать его для хранения аргументы в arg.

Действительно, у вас есть. Но вы также можете использовать некоторые встроенные функции для этого aka "shebang":
Вместо того, чтобы помещать имя файла в отдельный файл, добавьте так называемую shebang в качестве первой строки файла, который вы хотите для cat:

#!/bin/cat

И добавьте chmod +x к нему. Затем вы можете запустить его как исполняемый файл (через любую из функций exec или оболочку):

λ ~/tmp/ printf '#!/bin/cat\nTEST\n' > cat_me
λ ~/tmp/ chmod +x cat_me
λ ~/tmp/ ./cat_me 
#!/bin/cat
TEST

Из-за этого у него есть недостаток печати shebang сам с файлом, но все же это интересно сделать in-kernel =)

BTW. Проблема, которую вы описали, если так распространено, что существует специальный исполняемый файл с именем xargs, который (в очень упрощенном объяснении) выполняет данную программу в списке аргументов, переданных через stdin. Для получения дополнительной информации обратитесь к man xargs.


Для легкого запоминания exec -семейства я часто использую следующую таблицу:

           Figure 8.14. Differences among the six exec functions
+----------+----------+----------+----------+--------+---------+--------+
| Function | pathname | filename | agr list | argv[] | environ | envp[] |
+----------+----------+----------+----------+--------+---------+--------+
|  execl   |    *     |          |     *    |        |    *    |        |
+----------+----------+----------+----------+--------+---------+--------+
|  execlp  |          |    *     |     *    |        |    *    |        |
+----------+----------+----------+----------+--------+---------+--------+
|  execle  |    *     |          |     *    |        |         |   *    |
+----------+----------+----------+----------+--------+---------+--------+
|  execv   |    *     |          |          |    *   |    *    |        |
+----------+----------+----------+----------+--------+---------+--------+
|  execvp  |          |    *     |          |    *   |    *    |        |
+----------+----------+----------+----------+--------+---------+--------+
|  execve  |    *     |          |          |    *   |         |   *    |
+----------+----------+----------+----------+--------+---------+--------+
|  letter  |          |    p     |     l    |    v   |         |   e    |
+----------+----------+----------+----------+--------+---------+--------+

Итак, в вашем случае execvp принимает имя файла, argv (v) и environment ( e). Затем он пытается "угадать" путь (aka полный путь), добавив filename (в вашем случае cat) к каждому компоненту пути в PATH, пока не найдет путь с исполняемым filename.

Гораздо больше информации о том, что происходит с капотом exec (включая материал наследования), можно найти в Расширенное программирование в среде UNIX (второе издание) W. Richard Stevens и Стивен А. Раго, а также APUE2.
Если вас интересует внутренняя часть UNIX, вы, вероятно, должны ее прочитать.

Ответ 3

"ls" - это не просто команда, это на самом деле программа (большинство команд есть). Когда вы запустите execvp, он будет уничтожать всю вашу программу, ее память, стек, кучу и т.д.... концептуально "очистить" и передать его "ls" , чтобы он мог использовать его для собственного стека, куча и т.д.

Короче говоря, execvp уничтожит вашу программу и заменит ее другой программой, в данном случае "ls" .

Ответ 4

Моя интуиция заключается в том, что я должен прочитать файл и, возможно, проанализировать его для хранения аргументов в arg. Однако я хочу убедиться.

Ваша интуиция во многом правильна. Утилита cat, которую вы используете в качестве примера, имеет два отдельных пути кода:

  • Если имена файлов указаны как аргументы, они будут открывать и читать каждый по очереди.
  • Если указанных файлов не указано, они будут считываться со стандартного ввода.

Такое поведение специально реализовано в утилите cat - оно не реализовано ни на одном более низком уровне. В частности, он определенно не является частью системного вызова exec. Системные вызовы exec вообще не "рассматривают" аргументы; они просто передают их прямо на новый процесс в argv, и этот процесс позволяет обрабатывать их, но он считает нужным.