Por que precisamos passar o nome do arquivo duas vezes nas funções exec?

11

Eu li Programação Avançada no UNIX Ambiente por Stevens, 8 th capítulo. Eu li e compreendi todas as seis funções executivas.

Uma coisa que noto é que, em todas as funções exec:

  • O primeiro argumento é o nome do arquivo / nome do caminho (depende da função exec).
  • o segundo argumento é argv [0] que entramos main(), que é o próprio nome do arquivo.

Então, aqui temos que passar o nome do arquivo duas vezes na função

Existe alguma razão para isso (como não podemos obter o nome do arquivo no nome do caminho desde o primeiro argumento)?

munjal007
fonte

Respostas:

14

Então, aqui temos que passar o nome do arquivo duas vezes na função

Eles não são exatamente a mesma coisa que você observa, observando que um deles é usado como argv[0]valor. Isso não precisa ser o mesmo que o nome base do executável; muitas / a maioria das coisas o ignoram e você pode colocar o que quiser lá.

O primeiro é o caminho real para o executável, para o qual existe uma necessidade óbvia. O segundo é passado para o processo ostensivamente como o nome usado para invocá-lo, mas, por exemplo:

execl("/bin/ls", "banana", "-l", NULL);

Funcionará bem, presumindo que /bin/lsseja o caminho correto.

Alguns aplicativos, no entanto, fazem uso argv[0]. Normalmente, eles têm um ou mais links simbólicos $PATH; isso é comum nos utilitários de compactação (às vezes eles usam invólucros de shell). Se você xzinstalou, stat $(which xzcat)mostra que é um link para xze man xzcaté o mesmo man xzque explica "xzcat é equivalente a xz --decompress --stdout". A maneira como o xz pode dizer como foi invocada é verificando argv[0], tornando estes equivalentes:

execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);
Cachinhos Dourados
fonte
4
Ah, então isso explicaria como busyboxpode ser o que você quer, dependendo de como você chama isso certo?
terdon
3
@terdon é exatamente assim que o binário único para o busybox satisfaz tantos comandos diferentes.
mah
7
O que significaria que, se /bin/lsestivesse ocupado, não saberia como executar banana!
Riking
6

Você não precisa passar o nome do arquivo duas vezes.

O primeiro é o arquivo que é realmente executado.

O segundo argumento é qual deve ser o argv[0]do processo, ou seja, qual deve ser o nome do processo. Por exemplo, se você executar a lspartir do shell, o primeiro argumento é /bin/ls, o segundo é justo ls.

Você pode executar um determinado arquivo e chamá-lo de outra coisa através do segundo argumento; o programa pode verificar seu nome e se comportar de maneira diferente de acordo com o nome. Isso também pode ser feito através de links físicos (ou links simbólicos), mas dessa maneira oferece mais flexibilidade.

Wurtel
fonte
De fato, os links são o mesmo método, pois são definidos argv[0]como o nome do link.
509 goldilocks #
No último parágrafo, "Você pode executar um determinado arquivo e chamá-lo de outra coisa através do segundo argumento; o programa pode verificar seu nome e se comportar 'de maneira diferente' de acordo com o nome". você pode por favor elaborar ou me dar algumas leituras, eu sou novo neste ambiente.
precisa saber é o seguinte
A última parte da resposta dos goldilocks explica isso.
wurtel
1

O argumento é que argv[0]pode ser definido para qualquer coisa (inclusive NULL). Por convenção , argv[0]será definido como o caminho em que o executável foi iniciado (pelo processo do shell quando o faz execve()).

Se ./fooe houver dir/bardois links diferentes (físicos ou simbólicos) para o mesmo executável, iniciar o programa a partir do shell usando os dois caminhos será definido argv[0]como ./fooe dir/bar, respectivamente.

O fato de que argv[0]pode ser NULLé muitas vezes esquecido. O código a seguir pode travar por NULL argv[0]exemplo (embora o glibc imprima algo como <null> em vez disso argv[0]):

if (argc != 3) {
    fprintf(stderr, "%s: expected 2 arguments\n", argv[0]);
    exit(EXIT_FAILURE);
}

Uma alternativa no Linux é usar /proc/self/exepara esses casos.

Ulfalizer
fonte
como você pode conjunto argv [0] para ambos ./foo e dir bar /
munjal007
@ munjal007 Me desculpe se eu não estava sendo clara. Eu quis dizer executando o programa duas vezes: uma vez ./fooe uma vez como dir/bar. argv[0]será diferente para esses dois casos (em cada caso será o mesmo que o caminho que você usou).
Ulfalizer
@ munjal007 Isso pressupõe que você o execute a partir do shell, é claro. O ponto é que você pode definir argv[0]qualquer coisa quando você exec*()mesmo programa. É uma convenção do shell definir argv[0]o caminho usado para iniciar o programa (e é aconselhável fazer o mesmo quando você é exec*()um programa, pois muitos programas inspecionam argv[0]e esperam que ele mantenha o caminho).
Ulfalizer