Функция Linux exec: для чего используется параметр arg0?

вот прототип функции execlp:

int execlp(const char *file, const char *arg, ...);

на man-странице говорится, что первый аргумент arg(т. е. arg0), " по соглашению, должно указывать на имя файла, связанное с выполняемым файлом."

затем я сделал эти эксперименты:

/*These three lines all produce the expected result:
 .  ..  a.out  main.c */
execlp("ls", "ls", "-a", 0);
execlp("ls", "arg0 is meaningless", "-a" , 0);
execlp("ls", "", "-a" , 0);

/*But this one does not work:
 a.out  main.c */
execlp("ls", "-a" , 0);

Итак, вопрос в том, является ли параметр arg0 значимым при любых обстоятельствах? Почему интерфейс был разработан таким образом?

5 ответов


последний звонок

execlp("ls", "-a" , 0);

не имеет достаточных параметров для работы как предыдущие. Если вы вместо этого позвоните

execlp("ls", "-a" , "-a", 0);

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

обычно ls просто делает set_program_name (argv[0]), и это все, для чего он использует argv[0]. Смотри источник: http://git.savannah.gnu.org/gitweb/?p=coreutils.git;a=blob;f=src/ls.c;h=cd5996eb979f9e9319089e8c065b1276a1fbece8;hb=refs/heads/master - ... Этот вызов устанавливает переменную program_name, которая затем используется для печати usage

printf (_("Usage: %s [OPTION]... [FILE]...\n"), program_name);

вот почему вы получаете другой вывод справки, как показал Андрей.

как говорит Крис S, Некоторые программы кодируются по-разному в зависимости от того, как они были вызваны в терминах argv[0]. Но GNU ls не является одним из них программы. Честно говоря, я удивляюсь, почему нет, потому что они используют одни и те же ls.C-код для компиляции как ls, так и "dir" и "vdir", но они компилируются как разные двоичные файлы через ls-vdir.c и ls-реж.c. Есть заголовок, ls. h что имеет

#define LS_LS 1

/* This is for the 'dir' program.  */
#define LS_MULTI_COL 2

/* This is for the 'vdir' program.  */
#define LS_LONG_FORMAT 3

extern int ls_mode;

затем посмотрите в ls-vdir.C для пример. Весь файл состоит из

#include "ls.h"
int ls_mode = LS_LONG_FORMAT;

наконец вернуться к ls.c и теперь комментарии в верхней части, как

если ls_mode является LS_LONG_FORMAT, длинный формат по умолчанию независимо от тип выходного устройства. Это для программы "vdir".

должно начать иметь смысл.

некоторые люди даже думали, что доставка 3 двоичных файлов (ls, dir и vdir) вместо одного была ошибкой https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=16312 но это, по-видимому, по дизайну как последний комментарий в https://bugs.archlinux.org/task/2767 (цитата из http://www.gnu.org/prep/standards/html_node/User-Interfaces.html) говорит

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

таким образом, GNU не Unix ; -) хотя они могли бы заставить ls изменять свое поведение через argv[0], они решили не делать этого по философским причинам (и отправить вам три вместо двоичных файлов). Очевидно, что другие кодеры Unix (например, ребята из buysbox) не разделяют эту философию.


основная подписи функции

int main(int argc, char ** argv);

где argv[0] - имя исполняемого файла (arg0 в вашем случае), поэтому приложение ожидает свою командную строку от argv[1].

в некоторых случаях один двоичный файл может иметь несколько имен (с busybox, например, иногда использует символические ссылки с разными именами, указывая на один двоичный). В таких случаях argv[0] используется для определения, какая ссылка использовалась для вызова двоичного файла.


программы могут использовать argv[0] вести себя по-разному в зависимости от того, как они называются. Например, см. Этот фрагмент из args.c от xz-utils:

        const char *name = strrchr(argv[0], '/');
    if (name == NULL)
        name = argv[0];
    else
        ++name;

    // Look for full command names instead of substrings like
    // "un", "cat", and "lz" to reduce possibility of false
    // positives when the programs have been renamed.
    if (strstr(name, "xzcat") != NULL) {
        opt_mode = MODE_DECOMPRESS;
        opt_stdout = true;
    } else if (strstr(name, "unxz") != NULL) {
        opt_mode = MODE_DECOMPRESS;
    } else if (strstr(name, "lzcat") != NULL) {
        opt_format = FORMAT_LZMA;
        opt_mode = MODE_DECOMPRESS;
        opt_stdout = true;
    } else if (strstr(name, "unlzma") != NULL) {
        opt_format = FORMAT_LZMA;
        opt_mode = MODE_DECOMPRESS;
    } else if (strstr(name, "lzma") != NULL) {
        opt_format = FORMAT_LZMA;
    }

вы можете попробовать execlp("ls", "not_ls", "--help", 0) чтобы увидеть разницу. ls тогда будет обманут, думая, что это not_ls и напечатать что-то вроде:

Usage: not_ls [OPTION]... [FILE]...

Да, все параметры имеют смысл.

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

программа C получает все, кроме первого аргумента через argc и argv:

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

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