Pomyślałem więc, że dobrze to rozumiem, ale właśnie przeprowadziłem test (w odpowiedzi na rozmowę, w której nie zgadzałem się z kimś) i stwierdziłem, że moje rozumienie jest błędne ...
Jak bardzo szczegółowo, co dokładnie dzieje się, gdy wykonuję plik w mojej powłoce? Mam na myśli to, że jeśli napiszę : ./somefile some arguments
w mojej powłoce i naciśnie klawisz Return (i somefile
istnieje w cwd, a mam uprawnienia do odczytu + wykonywania somefile
), to co się stanie pod maską?
Myślałem, że odpowiedź brzmi:
- Powłoka wykonuje polecenie systemowe
exec
, przekazując ścieżkę dosomefile
- Jądro sprawdza
somefile
i sprawdza magiczną liczbę pliku, aby ustalić, czy jest to format obsługiwany przez procesor - Jeśli magiczna liczba wskazuje, że plik ma format, który procesor może wykonać, to
- tworzony jest nowy proces (z wpisem w tabeli procesów)
somefile
jest odczytywany / mapowany do pamięci. Tworzony jest stos, a wykonanie przeskakuje do punktu wejścia kodusomefile
, zARGV
zainicjalizowanym do tablicy parametrów (achar**
,["some","arguments"]
)
- Jeśli magiczna liczba to shebang, to
exec()
spawnuje nowy proces jak wyżej, ale użyty plik wykonywalny to interpreter, do którego odwołuje się shebang (np./bin/bash
Lub/bin/perl
) isomefile
jest przekazywany doSTDIN
- Jeśli plik nie ma prawidłowej magicznej liczby, pojawia się błąd typu „nieprawidłowy plik (zła magiczna liczba): błąd formatu Exec”
Jednak ktoś powiedział mi, że jeśli plik jest zwykłym tekstem, wówczas powłoka próbuje wykonać polecenia (tak jakbym napisał bash somefile
). Nie wierzyłem w to, ale po prostu spróbowałem i było to poprawne. Wyraźnie mam więc pewne nieporozumienia na temat tego, co się tu właściwie dzieje i chciałbym zrozumieć mechanikę.
Co dokładnie dzieje się, gdy wykonuję plik w mojej powłoce? (w najdrobniejszych szczegółach jest rozsądne ...)
source somefile
różni się jednak bardzo od nowego procesu, który został opracowany./somefile
../somefile
że spowoduje to, że bash wykona polecenia,somefile
jeśli plik nie będzie miał magicznej liczby. Myślałem, że po prostu wyświetli błąd, a zamiast tego wydaje się być skutecznysource somefile
somefile
jest to plik tekstowy, to jeśli spróbuję go uruchomić, pojawi się nowa powłoka. Plikecho $$
zachowuje się inaczej, jeśli wykonam go w stosunku do źródła.Odpowiedzi:
Ostateczną odpowiedzią na „jak uruchamiają się programy” w Linuksie jest para artykułów na LWN.net zatytułowanych, co zaskakujące, jak uruchamiać programy i jak uruchamiać programy: pliki binarne ELF . Pierwszy artykuł krótko opisuje skrypty. (Ściśle mówiąc, ostateczna odpowiedź znajduje się w kodzie źródłowym, ale artykuły te są łatwiejsze do odczytania i zawierają linki do kodu źródłowego).
Trochę eksperymentów pokazuje, że właściwie wszystko dobrze zrozumiałeś i że wykonanie pliku zawierającego prostą listę poleceń bez shebang musi być obsługiwane przez powłokę. Strona podręcznika execve (2) zawiera kod źródłowy programu testowego, execve; użyjemy tego, aby zobaczyć, co się stanie bez powłoki. Najpierw napisz testcript
testscr1
, zawierającyi kolejny
testscr2
, zawierający tylkoUstaw je jako pliki wykonywalne i sprawdź, czy oba działają z poziomu powłoki:
Teraz spróbuj ponownie, używając
execve
(zakładając, że wbudowałeś go w bieżący katalog):testscr1
nadal działa, aletestscr2
produkujeTo pokazuje, że powłoka działa
testscr2
inaczej. Jednak nie przetwarza samego skryptu, nadal używa/bin/sh
do tego celu; można to zweryfikować przesyłająctestscr2
doless
:W moim systemie mam
Jak widać, istnieje powłoka
zsh
, której używałem, która się rozpoczęłaless
, i druga powłoka, zwykłash
(dash
w moim systemie), do uruchomienia skryptu, który został uruchomionypstree
. Wzsh
ten jest obsługiwany przezzexecve
wSrc/exec.c
: skorupy zastosowańexecve(2)
spróbować uruchomić komendę, a jeśli to się nie powiedzie, to odczytuje plik, aby zobaczyć, czy posiada ono shebang, przetwarza je odpowiednio (co jądro będzie również zrobić), a jeśli to kończy się niepowodzeniem, próbuje uruchomić pliksh
, o ile nie odczytał z pliku żadnego bajtu zerowego:bash
ma to samo zachowanie, zaimplementowaneexecute_cmd.c
z pomocnym komentarzem (jak zauważył taliezin ):POSIX definiuje zestaw funkcji, zwany na
exec(3)
funkcje , które owijaneexecve(2)
i zapewnić tę funkcję też; szczegóły patrz odpowiedź muru . W Linuksie przynajmniej te funkcje są implementowane przez bibliotekę C, a nie przez jądro.źródło
Częściowo zależy to od konkretnej
exec
użytej funkcji rodziny.execve
, jak szczegółowo pokazał Stephen Kitt , uruchamia tylko pliki w poprawnym formacie binarnym lub skrypty, które zaczynają się od właściwego shebang.Jednakże ,
execlp
iexecvp
pójść o krok dalej: jeżeli shebang nie była prawidłowa, plik zostanie wykonany z/bin/sh
Linux. Odman 3 exec
:Jest to nieco wspierane przez POSIX (moje podkreślenie):
Nie określa to sposobu uzyskania interpretera poleceń, więc nie określa, że należy podać błąd. Sądzę więc, że deweloperzy Linuksa zezwalali na uruchamianie takich plików
/bin/sh
(lub była to już powszechna praktyka i po prostu poszły w ich ślady).FWIW, strona podręczna FreeBSD
exec(3)
również wspomina o podobnym zachowaniu:AFAICT nie ma jednak powszechnych zastosowań powłoki
execlp
lubexecvp
bezpośrednio, prawdopodobnie w celu uzyskania lepszej kontroli nad środowiskiem. Wszystkie wykorzystują tę samą logikęexecve
.źródło
execl
,execlp
,execle
,execv
,execvp
iexecvpe
są przednie końce doexecve
syscall; te pierwsze są dostarczane przez bibliotekę C, jądro zna tylkoexecve
(iexecveat
obecnie).Może to być dodatek do odpowiedzi Stephena Kitta jako komentarz ze
bash
źródła w plikuexecute_cmd.c
:źródło
To pobiera wykonywane jako skrypt powłoki, to nie pochodzą (na przykład, zmienne określone w zawartej pliku nie wpływają na zewnątrz). Prawdopodobnie ślad po mglistej przeszłości, kiedy istniała jedna powłoka i jeden format wykonywalny. To nie jest plik wykonywalny, musi to być skrypt powłoki.
źródło
exec()
czy to jest skorupa? Chcę znacznie więcej wewnętrznych