a pesquisa PATH inclui links simbólicos?

9

O padrão de shell POSIX diz neste site

http://pubs.opengroup.org/onlinepubs/9699919799/

sobre como os shells usam PATHpara procurar executáveis:

"A lista deve ser pesquisada do começo ao fim, aplicando o nome do arquivo a cada prefixo, até que um arquivo executável com o nome especificado e as permissões de execução apropriadas seja encontrado."

Bem, não é assim que isso parece funcionar na implementação real do POSIX:

man which diz:

"retorna os nomes de caminho dos arquivos (ou links) que seriam executados no ambiente atual, se seus argumentos fossem dados como comandos em um shell estritamente compatível com POSIX. Isso é feito pesquisando no PATH por arquivos executáveis ​​que correspondem aos nomes dos argumentos. Não segue links simbólicos ".

OK, vamos olhar para esta situação:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar

OK, aqui está um link simbólico PATHcom o nome correto e é relatado lscomo sendo executável.

which não olha nada, mas só está interessado no que aponta.

Isso apesar do fato de ambos man whichdizerem explicitamente que ele não segue links simbólicos (e, de fato, o vemos, porque which foobarnão imprime foobar1), e também que a documentação do shell POSIX citada acima, nunca menciona os links simbólicos no PATHalgoritmo.

Então, whichas conchas existentes estão erradas ou não estou entendendo a documentação?

ESCLARECER:

Eu sei e posso explicar o comportamento existente. Minha pergunta não é "como isso funciona?". Que eu saiba.

Minha pergunta é sobre documentação: onde está meu erro em seguir a documentação que citei. Ou a documentação está errada?

MOTIVAÇÃO: Por que eu me importo?

Bem, eu sou um implementador. Implementadores diferentes têm requisitos diferentes. Para mim, o requisito é que a palavra do padrão POSIX atual DEVE ser seguida EXATAMENTE (ou, mais precisamente, o melhor que pode ser, porque o próprio padrão é um tanto incorreto). Como se fosse a palavra de Deus.

Agora, a redação padrão é bastante clara - os links simbólicos a seguir não são mencionados, onde em muitos outros lugares, é mencionado onde precisa ser feito. Então, neste caso, não.

No entanto, eu sempre verifiquei como dashe me bashcomporte, apenas para ter certeza. Agora, é claro, também há um pequeno problema aqui, dashmesmo que seja anunciado como POSIX, possui muitos pequenos bugs com conformidade com o POSIX. bash, Ainda não encontrei nenhum bug com o POSIX, mas ... o bash não é realmente o POSIX, é muito mais do que isso.

Então aí está. É por isso que eu me importo.

user322908
fonte
Você não entende: o que não segue links simbólicos nos arquivos . $PATHcan contém links simbólicos. Tente which sh.
Ipor Sircer
OK, mas, no meu caso $PATH, não possui links simbólicos.
user322908
Em quase todas as situações, os links simbólicos são seguidos de forma transparente. Os casos em que não estão são geralmente mencionados explicitamente (por exemplo, chamadas de sistema como lstat(2)), segui-los geralmente não é indicado. Por exemplo, a descrição open(2)apenas menciona links simbólicos ao falar sobre o comportamento de O_CREAT | O_EXCL. Não é necessário declarar que o arquivo de destino será aberto.
Barmar

Respostas:

10

As permissões do próprio link simbólico são irrelevantes. Você nem poderia alterá-los se tentasse.

O que importa são as permissões do arquivo subjacente.

É bom ter diretórios em seu PATH incluir links simbólicos para executáveis. De fato, é provável que muitos executáveis ​​no seu PATH sejam links simbólicos. Por exemplo, em sistemas como o debian / ubuntu:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash

Documentação

De man chmod:

O chmod nunca altera as permissões de links simbólicos; a chamada do sistema chmod não pode alterar suas permissões. Isso não é um problema, pois as permissões de links simbólicos nunca são usadas. No entanto, para cada link simbólico listado na linha de comando, o chmod altera as permissões do arquivo apontado. Por outro lado, o chmod ignora os links simbólicos encontrados durante os percursos do diretório recursivo. [Enfase adicionada.]

Exemplo

O shell tem um teste, -xpara determinar se um arquivo é executável. Vamos tentar isso:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable

Portanto, assim como você encontrou which, o shell não considera um executável de link programável a menos que o arquivo subjacente seja executável.

Como funciona

Em um sistema Debian, whiché um script de shell. A seção relevante do código é:

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac

Como você pode ver, ele usa o -xteste para determinar se um arquivo é executável.

POSIX especifica o -xteste da seguinte maneira:

-x nome do caminho
True se o nome do caminho for resolvido para uma entrada de diretório existente para um arquivo cuja permissão para executar o arquivo (ou procurá-lo, se for um diretório) será concedida, conforme definido em Leitura, gravação e criação de arquivo. False se o nome do caminho não puder ser resolvido ou se o nome do caminho for resolvido para uma entrada de diretório existente para um arquivo cuja permissão para executar (ou pesquisar) o arquivo não será concedida. [Enfase adicionada.]

Portanto, o POSIX verifica o que o nome do caminho resolve . Em outras palavras, ele aceita links simbólicos.

Função exec POSIX

A função exec POSIX segue links simbólicos. A especificação do POSIX continua detalhadamente para especificar as condições de erro que podem ser relatadas se os links simbólicos forem circulares ou muito profundos, como:

[ELOOP]
Existe um loop nos links simbólicos encontrados durante a resolução do caminho ou argumento do arquivo.

[ELOOP]
Mais de links simbólicos {SYMLOOP_MAX} foram encontrados durante a resolução do caminho ou argumento do arquivo.
[ENAMETOOLONG]
Como resultado de encontrar um link simbólico na resolução do argumento do caminho, o comprimento da cadeia de nomes de caminhos substituída excedeu {PATH_MAX}.

John1024
fonte
EU SEI tudo que você escreveu na sua resposta. Eu sei como as coisas "funcionam". Essa não é a minha pergunta. Minha pergunta é sobre documentação. Aponte-me onde não estou entendendo a documentação. Ou diga-me que a documentação está incorreta.
user322908
@ user322908 Na maioria dos sistemas, whichexiste um shell script. Portanto, é provável que apenas usando o -xteste que mostrei. De acordo com o POSIX, -xtesta se um arquivo "resolve" para um executável. Se você está vendo algo diferente, para onde está olhando?
John1024
Obrigado e desculpe-me por sentir tanta dor ... Percebo que minha pergunta é diferente de 99%, por isso é difícil entender o que estou procurando. Novamente, não estou interessado em "como" whichfunciona, ou se é -xou algo mais. Estou interessado em saber onde não estou seguindo corretamente a documentação que citei.
user322908
4
@ user322908 A função POSIXexec segue links simbólicos. Isso parece deixar bem claro que os arquivos com links simbólicos podem ser executáveis ​​no POSIX.
John1024
2
Também verifiquei o Ubuntu 17.10, man which que diz "Ele não canoniza nomes de caminhos". Isso não significa que não segue os links. Isso significa apenas, como você observou, que não "canoniza" os nomes.
John1024
3

Nesse caso, os links simbólicos são seguidos de forma transparente, sem canonizar o caminho final. Em outras palavras, whichnão se importa se /home/mark/biné um link simbólico ou não. O que importa é se o arquivo /home/mark/bin/foobarexiste ou não. Ele não precisa nivelar manualmente os links simbólicos ao longo do caminho - o sistema operacional pode fazer isso sozinho.

E, de fato, quando whichpergunta sobre as informações do arquivo /home/mark/bin/foobar, o SO percebe /home/mark/binser um link simbólico, o segue e encontra com êxito foobarno diretório de destino.

Esse é o comportamento padrão, a menos que o programa use open(…, O_NOFOLLOW)ou fstatat(…, AT_SYMLINK_NOFOLLOW)acesse o arquivo.

[comentários mesclados]

Enquanto você dizer que os utilitários de shell fazê-lo numa base caso-a-caso, não é o mesmo com syscalls kernel: todas as chamadas de arquivo relacionada com fazer seguir os links por padrão, a menos que o flag "nofollow" é dada. (Mesmo o lstat segue links simbólicos em todos os componentes do caminho, exceto o último.)

Quando a especificação não menciona explicitamente o que fazer com links simbólicos, isso implica que o comportamento padrão será usado. Ou seja, um shell que segue o algoritmo de caminho que os neithers resolvem os links simbólicos manualmente nem exclui explicitamente o SO do sistema operacional. (Apenas concatena cada componente $ PATH com o nome do executável.)

Quando a página do manual what (1) diz que não segue links simbólicos, pode significar várias coisas, mas a versão do coreutils do GNU diz o seguinte:

O qual considerará dois diretórios equivalentes diferentes quando um deles contém um caminho com um link simbólico.

O escopo é muito mais restrito - significa apenas whichque não tentará canonizar manualmente todos os caminhos para eliminar duplicatas, mas isso não implica que a ferramenta desative o link simbólico seguido pelo SO em geral. Por exemplo, se /binfor um link simbólico para /usr/bin, a execução which -a shretornará ambos /bin/sh e /usr/bin/sh.

user1686
fonte
Sim, obrigado, eu sei tudo isso. Minha pergunta não é como as coisas "funcionam". Eu sei como eles funcionam. Esse não é o meu ponto. Meu ponto é sobre documentação. Onde estou seguindo a documentação incorretamente. Ou a documentação está incorreta.
user322908
2
Você está entendendo a documentação incorretamente - se ela não mencionar os links simbólicos a seguir, isso significa que não resolve manualmente os links simbólicos, mas o comportamento regular do SO ainda se aplica. A whichpágina de manual do GNU afirma de forma diferente: "O que considerará dois diretórios equivalentes diferentes quando um deles contém um caminho com um link simbólico".
user1686
OK, é melhor, obrigado! Eu estou tentando entender ... Mas ... perdoe minha dor no pescoço: "o comportamento regular do SO" NÃO é sempre seguir implicitamente links simbólicos. Existem muitos utilitários que não. É caso a caso.
user322908
11
Todas as chamadas do kernel - chdir, open, chmod, execve ... - seguirão links simbólicos no caminho e na cauda, ​​a menos que você especifique AT_SYMLINK_NOFOLLOW ou similar. (lstat é o único que não desrefere os links simbólicos no final, mas ainda o faz no caminho restante.) Portanto, o comportamento padrão é seguir os links simbólicos. Por exemplo, quando um shell chama execve("/home/mark/bin/foobar", …), todos os links simbólicos são seguidos.
user1686
OK, acho que estou comprando o execveargumento, na verdade, na minha implementação, é a execl()mesma coisa. Por favor, se você incluir isso na sua resposta, eu aceito.
user322908
1

O shell está em conformidade com sua documentação, pois segue as regras para a resolução do nome do caminho. whichestá de acordo com sua documentação. Os dois fazem coisas ligeiramente diferentes.

A saída de whiché o nome do arquivo e o caminho do link, não o caminho para o qual o link simbólico aponta. Isso está escrito na página de manual.

Quando um comando é executado, o link é "seguido" de acordo com a Seção 4.13 resolução Pathname na mesma . A cláusula relevante para a execução de um arquivo é:

Em todos os outros casos, o sistema deve prefixar o nome do caminho restante, se houver, com o conteúdo do link simbólico, exceto que se o conteúdo do link simbólico for a sequência vazia, a resolução do nome do caminho falhará com as funções que reportam um [ENOENT ] erros e utilitários que escrevem uma mensagem de diagnóstico equivalente ou o nome do caminho do diretório que contém o link simbólico devem ser usados ​​no lugar do conteúdo do link simbólico. Se o conteúdo do link simbólico consistir apenas em caracteres, todos os caracteres iniciais do nome do caminho restante serão omitidos do nome do caminho combinado resultante, deixando apenas os caracteres iniciais do conteúdo do link simbólico. Nos casos em que a prefixação ocorre, se o comprimento combinado exceder {PATH_MAX} e a implementação considerar que isso é um erro, a resolução do nome do caminho falhará com as funções que relatam um erro [ENAMETOOLONG] e os utilitários que escrevem uma mensagem de diagnóstico equivalente. Caso contrário, o nome do caminho resolvido será a resolução do nome do caminho recém-criado. Se o nome do caminho resultante não começar com a, o predecessor do primeiro nome do arquivo será considerado o diretório que contém o link simbólico.

Dave
fonte