Czy POSIX gwarantuje ścieżki do standardowych narzędzi?

22

Z C, jaki jest najłatwiejszy sposób uruchomienia standardowego narzędzia (np. Ps), a żadnego innego?

Czy POSIX gwarantuje na przykład, że standard psjest włączony, /bin/psczy powinienem zresetować zmienną środowiskową PATH do tego, co otrzymuję, confstr(_CS_PATH, pathbuf, n);a następnie uruchomić narzędzie poprzez wyszukiwanie PATH?

PSkocik
źródło
Mam z tyłu głowy, że POSIX mówi, że dla szeregu poleceń, w tym ed (1) (co jest ważne dla mksh ), że jeśli są one dostępne, muszą one być również dostępne poniżej /bin, tj. /bin/edMuszą być użyteczne jeśli ed jest zainstalowany. Nie mogę go teraz znaleźć, ale wiem, że LSB zależy od tego, i skutecznie broniłem raportów o błędach, używając tego jako uzasadnienia, więc przynajmniej w pewnym momencie musiało to być prawdą. (Lub było to coś innego niż POSuX i źle pamiętam, ale reszta jest prawdą.)
mirabilos

Odpowiedzi:

33

Nie, nie robi tego, głównie dlatego, że nie wymaga domyślnej zgodności systemów ani zgodności tylko ze standardem POSIX (z wyłączeniem jakiegokolwiek innego standardu).

Na przykład Solaris (system z certyfikatem zgodności) wybrał wsteczną kompatybilność swoich narzędzi /bin, co wyjaśnia, dlaczego zachowują się one w tajemniczy sposób, i zapewnia narzędzia zgodne z POSIX w oddzielnych lokalizacjach ( /usr/xpg4/bin, /usr/xpg6/bin... dla różnych wersji XPG (teraz scalonych) do standardu POSIX), które faktycznie są częścią opcjonalnych komponentów Solaris).

Nawet shnie ma gwarancji, że wejdzie /bin. W Solarisie /bin/shbyła to powłoka Bourne'a (więc nie jest zgodna z POSIX) aż do Solaris 10, podczas gdy teraz jest to ksh93 w Solaris 11 (wciąż nie w pełni zgodna z POSIX, ale w praktyce bardziej niż /usr/xpg4/bin/sh).

W C możesz exec*p()założyć i założyć, że jesteś w środowisku POSIX (w szczególności w odniesieniu do PATHzmiennej środowiskowej).

Możesz także ustawić PATHzmienną środowiskową

#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"...);

Lub możesz określić w czasie kompilacji ścieżkę narzędzi POSIX, które chcesz uruchomić (pamiętając, że w niektórych systemach, takich jak GNU, potrzebujesz więcej kroków, takich jak ustawienie POSIXLY_CORRECTzmiennej w celu zapewnienia zgodności).

Możesz także spróbować takich rzeczy jak:

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

W nadziei, że to shsię $PATH, że jest podobny do Bourne, że istnieje również getconfi to, że jest to jedna z wersji POSIX jesteś zainteresowany.

Stéphane Chazelas
źródło
Więc co robisz dla # !?
Joshua
13
@Joshua: Modlisz się, że /usr/bin/envistnieje i jest w większości zgodny z POSIX.
Kevin
3
@Kevin lub zapoznasz się z dziwactwami swojego palaeo-unixa i dostosujesz #! wiersz, aby użyć poprawnej ścieżki.
cas
3
@Kevin: Nie. /usr/bin/envTo jeszcze mniej przenośny (w praktyce) hack niż /bin/sh. Za POSIX, przenośny sposób napisać skrypt jest z nie #!w ogóle . Jeśli plik jest wykonywalny, ale ENOEXEC(nie jest to poprawny plik binarny), execvpnależy go wykonać za pomocą standardowej powłoki. :-) Oczywiście w praktyce jest to zły pomysł i powinieneś go po prostu użyć #!/bin/sh.
R ..
2
@GeoffNixon, ta część, do której się odnosisz, jest alternatywą, gdy nie, nie możesz lub nie chcesz używać _POSIX_C_SOURCE. Wykonuje ustawienie $PATHz powłoki zamiast z C.
Stéphane Chazelas
3

Właściwie w większości odpowiedziałbym tak . POSIX gwarantuje:

  1. To nie jest absolutna ścieżki a do zgodnych ze standardami wersji każdej określonej użyteczności,
  2. I, że musisz być w stanie znaleźć tę absolutną ścieżkę i być w stanie uruchomić to narzędzie.

Chociaż nie jest koniecznie zagwarantowane, że każde narzędzie powinno znajdować się w określonym katalogu we wszystkich systemach (/bin/ps ), to zawsze gwarantowane , aby móc znaleźć można w domyślnym PATH systemu, jako plik wykonywalny.

Rzeczywiście, jedynym sposobem określonym w standardzie, aby to zrobić w standardzie jest (w C) za pomocą unistd.h_CS_PATH lub w powłoce, za pomocą kombinacji commandi getconfnarzędzi, tj. PATH="$(command -p getconf PATH)" command -v psZawsze musi zwracać unikalną bezwzględną ścieżkę zgodną z POSIX psdostarczane w określonym systemie. Oznacza to, że o ile ścieżki są zdefiniowane w implementacji, które ścieżki są zawarte w domyślnej zmiennej systemowej PATH, są one wykorzystywane muszą być zawsze dostępne, unikalne i zgodne, w jednej ze ścieżek tam określonych.

Patrz: < unistd.h >, polecenie .

Geoff Nixon
źródło
Ale dla sh jest problem z jajkiem i kurczakiem. Działa PATH=$(command -p getconf PATH)to tylko z powłoki POSIX w środowisku POSIX. POSIX nie określa, w jaki sposób wchodzisz do tego środowiska, wystarczy, że zostanie to udokumentowane. Na przykład w systemie Solaris masz a /usr/xpg4/bin/getconfi a, /usr/xpg6/bin/getconfktóre zwracałyby różne wartości dla _CS_PATHdwóch różnych wersji standardu, i żadna z nich /usr/xpg4/binnie /usr/xpg6/binma wartości domyślnej $PATH. Jest taki, /usr/bin/getconfktóry IIRC zapewnia zgodność z XPG4.
Stéphane Chazelas
Czy dotyczy to nawet wersji Solaris 11+ (z certyfikatem UNIX 03+)? Zawsze czytałem: `` Aplikacje ... powinny być określone przez zapytanie PATH zwrócone przez getconf PATH, upewniając się, że zwracana ścieżka jest absolutną ścieżką, a nie wbudowaną powłoką. Na przykład, aby określić lokalizację standardowego narzędzia sh: polecenie -v sh W niektórych implementacjach może to zwrócić: / usr / xpg4 / bin / sh `` '' oznacza to, że musi to być wpis zgodny shz POSIX z dowolnej domyślnej powłoki .
Geoff Nixon
1
W POSIX nie ma nic, co powiedziałoby, że getconfw domyślnym $PATHsystemie powinien znajdować się rozkaz . Na przykład uzyskanie środowiska POSIX może wymagać uruchomienia warstwy emulacji, bez której w ogóle nie uruchomiłbyś żadnego polecenia podobnego do Uniksa (na przykład Windows). Gdy jesteś w środowisku zgodnym, getconf PATH będzie Ci $PATHsię dostać do mediów zgodnych, ale jeśli były w środowisku POSIX, który był już prawdopodobnie w tym przypadku. Pamiętaj, że getconf psmoże wrócić ps. Mając na pspolecenie wbudowane jest dozwolone.
Stéphane Chazelas