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

8

Eu li o Programação Avançada no Ambiente UNIX pelo capítulo Stevens, 8 th . Eu leio e entendo todas as seis funções do exec.

Uma coisa que eu noto é, 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 obtemos em main() , que é o nome do arquivo em si.

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 do nome do caminho do primeiro argumento)?

    
por munjal007 02.03.2015 / 12:33

3 respostas

13

So here we do have to pass the file name twice in the function.

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

O primeiro é o caminho real para o executável, para o qual há 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/ls é o caminho correto.

No entanto, algumas aplicações utilizam argv[0] . Geralmente, eles possuem um ou mais links simbólicos em $PATH ; isso é comum com utilitários de compactação (às vezes eles usam invólucros de shell). Se você tem xz instalado, stat $(which xzcat) mostra que é um link para xz e man xzcat é o mesmo que man xz , o que explica que "xzcat é equivalente a xz --decompress --stdout". A maneira que o xz pode dizer como foi invocado é verificando argv[0] , tornando-os equivalentes:

execl("/bin/xz", "xzcat", "somefile.xz", NULL);
execl("/bin/xz", "xz", "--decompress", "--stdout", "somefile.xz", NULL);
    
por 02.03.2015 / 12:56
5

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

O primeiro é o arquivo que é realmente executado.

O segundo argumento é o que deve ser o argv[0] do processo, ou seja, o que o processo deve ver como seu nome. Por exemplo. Se você executar ls do shell, o primeiro argumento será /bin/ls , o segundo será apenas 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 hard links (ou links simbólicos), mas desta forma dá mais flexibilidade.

    
por 02.03.2015 / 12:54
1

A conclusão é que argv[0] pode ser definido como qualquer coisa (incluindo NULL ). Por convenção , argv[0] será definido como o caminho em que o executável foi iniciado (pelo processo do shell quando ele executa o execve() ).

Se ./foo e dir/bar forem dois links diferentes (duros ou simbólicos) para o mesmo executável, iniciar o programa a partir do shell usando os dois caminhos definirá argv[0] to ./foo e dir/bar , respectivamente.

O fato de que argv[0] pode ser NULL é frequentemente ignorado. O código a seguir pode falhar por NULL argv[0] , por exemplo (embora a glibc imprima algo como em vez de argv[0] ):

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

Uma alternativa no Linux é usar /proc/self/exe para tais casos.

    
por 02.03.2015 / 15:05