exec

Rodzina wywołań systemowych, które zastępują bieżący proces nowym programem, zachowując ten sam PID. Często używane zaraz po fork do uruchomienia innego polecenia.

exec to rodzina wywołań systemowych w systemach uniksowych, która podmienia obraz bieżącego procesu na zupełnie nowy program — przy zachowaniu tego samego PID. Mówiąc po ludzku: proces, który był dotąd np. powłoką, „znika” i w jego miejsce wskakuje inny plik wykonywalny. Nie powstaje nowy proces, nie ma rodzica i dziecka — to ten sam wpis w tablicy procesów, tylko z innym kodem, innym segmentem pamięci i innym stosem.

Jak to działa i po co

W libc exec występuje jako kilka wariantów: execl, execlp, execv, execvp, execve, execvpe. Litery w nazwie mówią o argumentach: l to lista argumentów po przecinku, v to wektor (tablica), p oznacza szukanie programu w PATH, a e przekazanie własnego środowiska. Pod spodem wszystkie sprowadzają się do jednego prawdziwego wywołania jądra — execve (na Linuksie istnieje też nowsze execveat).

Kluczowa rzecz: jeśli exec się powiedzie, kod po nim już się nie wykona — bo nie ma do czego wracać, stary program przestał istnieć. Dlatego exec zwraca cokolwiek (czyli -1) tylko wtedy, gdy zawiedzie, np. plik nie istnieje albo brak uprawnień. To zachowanie jest fundamentem modelu fork + exec: proces najpierw się klonuje przez fork, a potem dziecko robi exec, żeby stać się docelowym programem. Rodzic zostaje sobą i może czekać przez wait.

Przykład z praktyki

Tak właśnie działa każda powłoka. Gdy w bash wpiszesz ls, shell robi fork, a dziecko woła execvp("ls", ...). W skryptach przyda Ci się wbudowane polecenie exec, które robi to bez forka — w samej powłoce:

  • exec ./serwer w skrypcie startowym (entrypoint kontenera) — serwer dostaje PID 1, dzięki czemu poprawnie odbiera sygnały typu SIGTERM przy docker stop.
  • exec 2>log.txt przekierowuje błędy całego skryptu do pliku, bez uruchamiania nowego programu.

Częste pułapki

Nie myl exec z system() czy forkexec sam w sobie nie tworzy nowego procesu, tylko zastępuje istniejący. Pamiętaj też, że deskryptory plików domyślnie przeżywają exec (chyba że ustawisz flagę O_CLOEXEC) — stąd działają potoki i przekierowania. I klasyk debugowania: jeśli „kod po exec się nie wykonuje”, to znaczy, że wszystko jest OK, a nie że masz buga.

Pojęcia powiązane: fork, wait, PID, execve, PATH, O_CLOEXEC, sygnały (SIGTERM), proces zombie.