Путаница с параметрами execve

У меня есть программа, написанная моим профессором, которая печатает рабочий каталог (pwd) с помощью execve(), но я не понимаю параметров.

pid_t pid = fork();

if(pid <0)
   perror(NULL);
else if(pid == 0)
{
   char*argv[] = {"pwd",NULL};
   execve("/bin/pwd",argv,NULL);
   perror(NULL);
}
else
    printf("Im the parent!");
return 0;
}

"/bin/pwd" указывает путь к исполняемому файлу, который будет выполняться.

Это означает, что он вызовет функцию pwd, не так ли? Тогда зачем мне нужен параметр pwd?

Не могла бы программа работать без этого параметра?


person Andrei Manolache    schedule 25.11.2019    source источник


Ответы (3)


По соглашению первым аргументом, передаваемым программе, является имя исполняемого файла. Однако это не обязательно должно быть.

В качестве примера возьмем следующую программу:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int i;

    printf("number of arguments: %d\n", argc);
    printf("program name: %s\n", argv[0]);
    for (i=1; i<argc; i++) {
        printf("arg %d: %s\n", argv[i]);
    }
    return 0;
}

Если вы запустите эту программу из другой, вот так:

char*argv[] = {"myprog", "A", "B", NULL};
execve("/home/dbush/myprog",argv,NULL);

Выше будет вывод:

number of arguments: 3
program name: myprog
arg 1: A
arg 2: B

Но вы также можете запустить его так

char*argv[] = {"myotherprog", "A", "B", NULL};
execve("/home/dbush/myprog",argv,NULL);

И он выведет:

number of arguments: 3
program name: myotherprog
arg 1: A
arg 2: B

Вы можете использовать значение argv[0] как способ узнать, как была вызвана ваша программа, и, возможно, предоставить различные функции на основе этого.

Популярный инструмент busybox делает именно это. Один исполняемый файл связан с разными именами файлов. В зависимости от того, какую ссылку пользователь использовал для запуска исполняемого файла, он может прочитать argv[0], чтобы узнать, был ли он вызван как ls, ps, pwd и т. д.

person dbush    schedule 25.11.2019
comment
Хорошим сравнением является заголовок HTTP Host, который делает то же самое для веб-сайтов. - person that other guy; 26.11.2019
comment
Когда мы выдаем: pwd, он печатает рабочий каталог в следующей строке, но вызов /bin/pwd/ в программе C печатает рабочий каталог в первой строке терминала. - person EsmaeelE; 26.11.2019

Об этом упоминается на справочной странице execve. Акцент мой.

По соглашению, первая из этих строк должна содержать имя файла, связанного с исполняемым файлом.

То есть на самом деле не обязательно, чтобы первым argv было имя файла. На самом деле это можно проверить, изменив argv[0] на любую строку в примере кода, и результат все равно будет правильным.

Так что на самом деле это просто условность. Многие программы используют argv[0] и ожидают, что это будет имя файла. Но многие программы также не заботятся о argv[0] (например, pwd). Таким образом, нужно ли на самом деле устанавливать argv[0] в имя файла, зависит от того, какая программа выполняется. Сказав это, было бы разумно всегда следовать условности, чтобы хорошо играть с давними ожиданиями почти всех.

person kaylum    schedule 25.11.2019

С man-страницы execve: http://man7.org/linux/man-pages/man2/execve.2.html

   argv is an array of argument strings passed to the new program.  By
   convention, the first of these strings (i.e., argv[0]) should contain
   the filename associated with the file being executed.  envp is an
   array of strings, conventionally of the form key=value, which are
   passed as environment to the new program.  The argv and envp arrays
   must each include a null pointer at the end of the array.

Таким образом, argv рассматривается как аргументы командной строки для выполнения новой программы. Поскольку по умолчанию для бинарного файла Linux, вызываемого с аргументами, доступ к этим аргументам осуществляется через argc/argv, где argv[0] содержит имя программы.

Я думаю, что это сделано для того, чтобы четность поведения соответствовала случаю по умолчанию (программа вызывается с аргументами).

Из источника: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/exec.c#l1376

argv, переданный в execve, используется для создания argv для запускаемого двоичного файла.

person brokenfoot    schedule 25.11.2019