O POSIX garante os caminhos para quaisquer utilitários padrão?

22

Em C, qual é a maneira mais fácil de executar um utilitário padrão (por exemplo, ps) e nenhum outro?

Does POSIX garantia de que, por exemplo, um padrão psestá em /bin/psou devo redefinir a variável de ambiente PATH para que eu recebo com confstr(_CS_PATH, pathbuf, n);e, em seguida, executar o utilitário através PATH-search?

PSkocik
fonte
Tenho em mente que o POSIX diz, para vários comandos, entre eles ed (1) (o que é importante para o mksh ), que, se estiverem disponíveis, também devem ser acessíveis sob /bin, ou seja, /bin/eddevem ser utilizáveis se ed estiver instalado. Não consigo encontrá-lo agora, mas sei que o LSB depende disso e defendi com êxito os relatórios de erros usando isso como justificativa, portanto, pelo menos, deve ter sido verdade em algum momento. (Ou era algo diferente de POSuX e eu lembro errado, mas o resto é verdade.)
mirabilos

Respostas:

33

Não, principalmente porque não exige que os sistemas estejam em conformidade por padrão ou em conformidade com apenas com o padrão POSIX (com exclusão de qualquer outro padrão).

Por exemplo, o Solaris (um sistema compatível certificado) escolheu a compatibilidade com versões anteriores de seus utilitários /bin, o que explica por que eles se comportam de maneiras misteriosas e fornece utilitários compatíveis com POSIX em locais separados (/usr/xpg4/bin , /usr/xpg6/bin... para diferentes versões do XPG (agora mescladas) no padrão POSIX), sendo parte dos componentes opcionais do Solaris).

shNão é garantido que Even esteja presente /bin. No Solaris,/bin/sh costumava ser o shell Bourne (não compatível com POSIX) até o Solaris 10, enquanto agora é ksh93 no Solaris 11 (ainda não totalmente compatível com POSIX, mas na prática é mais do que isso /usr/xpg4/bin/sh).

Em C, você pode usar exec*p()e assumir que está em um ambiente POSIX (em particular no que diz respeito àPATH variável de ambiente).

Você também pode definir a PATHvariável de ambiente

#define _POSIX_C_SOURCE=200809L /* before any #include */
...
confstr(_CS_PATH, buf, sizeof(buf)); /* maybe append the original
                                      * PATH if need be */
setenv("PATH", buf, 1);
exec*p("ps"...);

Ou você pode determinar em tempo de construção o caminho dos utilitários POSIX que deseja executar (tendo em mente que em alguns sistemas como o GNU, você precisa de mais etapas, como definir uma POSIXLY_CORRECTvariável para garantir a conformidade).

Você também pode tentar coisas como:

execlp("sh", "sh", "-c", "PATH=`getconf PATH`${PATH+:$PATH};export PATH;"
                         "unset IFS;shift \"$1\";"
                         "exec ${1+\"$@\"}", "2", "1", "ps", "-A"...);

Na esperança de que há um shem $PATH, que é Bourne-like, que há também um getconfe que é a pessoa certa para a versão do POSIX você está em interessado.

Stéphane Chazelas
fonte
Então, o que você faz para # !?
Joshua
13
@ Josué: Você reza para que /usr/bin/envexista e seja principalmente compatível com POSIX.
Kevin
3
@ Kevin ou você se familiariza com as peculiaridades do seu palaeo-unix e ajusta o #! linha para usar o caminho correto.
cas
3
@ Kevin: Não. /usr/bin/envÉ um hack ainda menos portátil (na prática) do que /bin/sh. De acordo com o POSIX, a maneira portátil de escrever um script de shell é absolutamente inexistente#! . Se um arquivo é executável, mas ENOEXEC(não é um binário válido), execvpé para executá-lo através do shell padrão. :-) Obviamente, na prática, essa é uma péssima idéia e você deve apenas usá-la #!/bin/sh.
R ..
2
@ GeoffNixon, essa parte a que você está se referindo é uma alternativa para quando você não usa, não pode ou não deseja usar _POSIX_C_SOURCE. Ele faz a configuração do $PATHshell em vez do C.
Stéphane Chazelas
3

Na verdade, eu responderia sim . O POSIX garante:

  1. Que existe é um caminho de uma absoluta para a versão compatível com os padrões de cada utilitário especificado,
  2. E que você deve conseguir encontrar esse caminho absoluto e executar esse utilitário.

Embora não seja necessariamente garantido que cada utilitário esteja em um diretório específico em todos os sistemas ( /bin/ps), ele sempre garantiu poderá ser encontrado no PATH padrão do sistema, como um arquivo executável.

De fato, a única maneira especificada para fazer isso no padrão é (em C) via unistd.h_CS_PATH, ou no shell, por meio de uma combinação de commande getconfutilitários, ou seja, PATH="$(command -p getconf PATH)" command -v psdeve sempre retornar o caminho absoluto exclusivo do POSIX compatível com POSIX psfornecido em um sistema específico. Ou seja, embora seja definido na implementação quais caminhos estão incluídos na variável PATH padrão do sistema, esses utilitários sempre devem estar disponíveis, exclusivos e compatíveis, em um dos caminhos especificados nele.

Veja: < unistd.h >, comando .

Geoff Nixon
fonte
Mas, sh, há um problema de galinha e ovo. Isso PATH=$(command -p getconf PATH)funcionará apenas a partir de um shell POSIX em um ambiente POSIX. O POSIX não especifica como você entra nesse ambiente, apenas que seja documentado. Por exemplo, no Solaris, você tem um /usr/xpg4/bin/getconfe um /usr/xpg6/bin/getconfque retornariam valores diferentes para_CS_PATH para as duas versões diferentes do padrão e /usr/xpg4/binnem /usr/xpg6/binestão no valor padrão de $PATH. Existe um /usr/bin/getconfque o IIRC oferece a você em conformidade com XPG4.
Stéphane Chazelas 04/09
Isso é válido mesmo para as versões Solaris 11+ (certificada UNIX 03+)? Eu sempre li `` Os aplicativos ... devem ser determinados pela interrogação do PATH retornado pelo getconf PATH, garantindo que o nome do caminho retornado seja um nome de caminho absoluto e não um shell interno . Por exemplo, para determinar a localização do utilitário sh padrão: command -v sh Em algumas implementações, isso pode retornar: / usr / xpg4 / bin / sh `` `significa que isso deve ser uma entrada para um compatível com POSIX a shpartir de qualquer shell padrão .
Geoff Nixon
1
Não há nada no POSIX que diga que deve haver um getconf comando no padrão $PATHde um determinado sistema. Por exemplo, obter um ambiente POSIX pode envolver o início de uma camada de emulação, sem a qual você não executaria nenhum comando semelhante ao Unix (pense no Windows, por exemplo). Quando você estiver em um ambiente compatível, getconf PATH você $PATHterá acesso a utilitários compatíveis, mas se você estivesse em um ambiente POSIX, provavelmente já era esse o caso. Observe que getconf pspode retornar ps. Tendo psembutido é permitido.
Stéphane Chazelas 04/09