Provided by: manpages-pl-dev_0.7-2_all bug

NAZWA

       execve - uruchomienie programu

SKŁADNIA

       #include <unistd.h>

       int execve(const char *filename, char *const argv[],
        char *const envp[]);

OPIS

       execve()  wykonuje  program wskazywany przez filename. filename musi być albo wykonywalnym
       plikiem binarnym, albo skryptem zaczynającym się od linii w postaci:

           #! interpreter [opcjonalny-parametr]

       Szczegóły  tego  ostatniego  przypadku  można  znaleźć  poniżej   w   rozdziale   "Skrypty
       interpretowane".

       argv  jest  tablicą  łańcuchów  przekazywanych  jako  argumenty nowego programu. Zgodnie z
       konwencją pierwszy z  nich  powinien  zawierać  nazwę  pliku  skojarzonego  z  wykonywanym
       programem. envp jest tablicą łańcuchów postaci klucz=wartość, która jest przekazywana jako
       środowisko do nowego programu. Zarówno argv, jak i envp muszą być  zakończone  wskaźnikiem
       pustym  (NULL). Tablica argumentów oraz środowisko są dostępne w funkcji main wywoływanego
       programu, jeżeli jest ona zdefiniowana jako:

           int main(int argc, char *argv[], char *envp[])

       W razie powodzenia execve() nie powraca, a sekcje tekstu, danych, bss i stos  wywołującego
       procesu są nadpisywane odpowiednimi sekcjami ładowanego programu.

       Jeśli  obecny  program  jest śledzony za pomocą ptrace, wysyła się mu SIGTRAP po pomyślnym
       execve().

       Jeżeli plik programu wskazywany przez filename ma ustawiony bit  set-user-ID  i  plik  ten
       jest  umieszczony  na  systemie  plików zamontowanym bez opcji nosuid (znacznika MS_NOSUID
       wywołania mount(2)) oraz proces wywołujący nie jest  śledzony  (ptrace(2)),  to  efektywny
       identyfikator  użytkownika  procesu  wywołującego  jest  ustawiany  na  właściciela  pliku
       programu. Podobnie,  jeżeli  dla  pliku  programu  ustawiony  jest  bit  set-group-ID,  to
       efektywnemu  identyfikatorowi  grupy  procesu  wywołującego  jest przypisywana grupa pliku
       programu.

       Efektywny  identyfikator  użytkownika  jest  kopiowany  do   saved-set-user-ID;   podobnie
       efektywny  identyfikator grupy jest kopiowany do saved-set-group-ID. Kopiowanie odbywa się
       po  zmianie  któregokolwiek  z  efektywnych  identyfikatorów  związanej  z  bitami   trybu
       set-user-ID i set-group-ID.

       Jeśli  program wykonywalny jest skonsolidowany dynamicznie w formacie a.out z bibliotekami
       dzielonymi, to na początku uruchamiania wywoływany jest konsolidator dynamiczny  ld.so(8),
       który ładuje wszystkie obiekty do pamięci i konsoliduje z nimi program wykonywalny.

       Jeżeli  program  jest  skonsolidowany  dynamicznie jako ELF, to do załadowania potrzebnych
       obiektów współdzielonych używany jest interpreter określony  w  segmencie  PT_INTERP.  Tym
       interpreterem  jest  zazwyczaj  /lib/ld-linux.so.2, w wypadku programów skonsolidowanych z
       glibc2 (zob. ld-linux.so(8)).

       Wszystkie atrybuty procesu są zachowywane podczas execve(), z wyjątkiem poniższych:

       *  Ustawienia obsługi sygnałów, które są przechwytywane, są zmieniane na wartości domyślne
          (signal(7)).

       *  Alternatywny stos sygnałów nie jest zachowywany (sigaltstack(2)).

       *  Mapowania pamięci nie są zachowywane (mmap(2))

       *  Dołączone segmenty pamięci dzielonej Systemu V są odłączane (shmat(2)).

       *  Regiony pamięci dzielonej POSIX są odmapowane (shm_open(3)).

       *  Otwarte kolejki komunikatów POSIX są zamykane (mq_overview(7)).

       *  Otwarte semafory nazwane POSIX są zamykane (mq_overview(7)).

       *  Timery POSIX nie są zachowywane (timer_create(2)).

       *  Otwarte strumienie katalogów są zamykane (opendir(3)).

       *  Blokady pamięci nie są zachowywane (mlock(2), mlockall(2)).

       *  Zarejestrowanie   funkcje  wykonywanych  po  zakończeniu  procesu  nie  są  zachowywane
          (atexit(3), on_exit(3)).

       *  Środowisko zmiennoprzecinkowe jest ustawiane na domyślne (patrz fenv(3)).

       Atrybuty procesu w liście przedstawionej  powyżej  są  określone  w  POSIX.1.  Następujące
       specyficzne dla Linuksa atrybuty procesu również nie są zachowywane podczas execve():

       *  Znacznik  PR_SET_DUMPABLE  prctl(2)  jest  ustawiany,  chyba  że  wykonywany program ma
          ustawiony bit set-user-ID lub  set-group-ID,  w  którym  przypadku  znacznik  ten  jest
          czyszczony.

       *  Znacznik PR_SET_KEEPCAPS prctl(2) jest czyszczony.

       *  (Od  Linuksa 2.4.36 / 2.6.23) Jeśli wykonywany program ma ustawiony bit set-user-ID lub
          set-group-ID, to jest czyszczony znacznik  PR_SET_PDEATHSIG   sygnału  śmierci  rodzica
          ustawiony przez  prctl(2).

       *  Nazwa  procesu  ustawiona przez PR_SET_NAME z prctl(2) (i wyświetlana przez ps -o comm)
          jest ustawiana na nazwę nowego pliku wykonywalnego.

       *  Znacznik SECBIT_KEEP_CAPS w securebits jest czyszczony. Patrz capabilities(7).

       *  Sygnał zakończenia jest ustawiany na SIGCHLD (patrz clone(2)).

       *  Tablica deskryptora plików nie jest dzielona, co anuluje  działanie  flagi  CLONE_FILES
          clone(2).

       Dalsze uwagi:

       *  Wszystkie  wątki  oprócz  wątku  wywołującego  są  niszczone podczas execve(). Muteksy,
          zmienne warunkowe i inne obiekty pthreads nie są zachowywane.

       *  Odpowiednik setlocale(LC_ALL, "C") jest wykonywany po uruchomieniu programu.

       *  POSIX.1 określa, że ustawienie procedur obsługi sygnału na ignorowanie lub  na  wartość
          domyślną  jest  pozostawiane bez zmian. POSIX.1 przewiduje jeden wyjątek od tej reguły:
          jeśli SIGCHLD jest ignorowany, to implementacja może albo nie zmienić tego  ustawienia,
          albo przestawić je na wartość domyślną; Linux robi to pierwsze.

       *  Wszystkie   asynchroniczne   operacje   wejścia/wyjście   są   anulowane  (aio_read(3),
          aio_write(3)).

       *  Sposób   obsługi   atrybutów   (zdolności)   procesu   podczas   execve()   opisano   w
          capabilities(7).

       *  Domyślnie   deskryptory  plików  pozostają  otwarte  po  execve().  Deskryptory  plików
          oznaczone jako "close-on-exec" są zamykane, patrz opis FD_CLOEXEC  w  fcntl(2).  (Jeśli
          deskryptor  pliku  zostanie  zamknięty, to zwolnione zostaną wszystkie blokady rekordów
          dotyczące pliku związanego z tym deskryptorem. Szczegóły  można  znaleźć  w  fcntl(2)).
          POSIX.1  mówi,  że  jeżeli deskryptory plików 0, 1 i 2 zostałyby zamknięte po pomyślnym
          wykonaniu execve(), a proces uzyskałby przywileje z powodu ustawionego  na  wykonywanym
          pliku  bitu  trybu  set-user-ID  lub  set-group-ID,  to  system  może  otworzyć  bliżej
          nieokreślony plik dla każdego z tych deskryptorów plików. Jako zasadę  należy  przyjąć,
          że  żaden  przenośny  program,  uprzywilejowany  czy nie, nie może zakładać, że te trzy
          deskryptory plików będą zamknięte po execve().

   Skrypty interpretowane
       Skrypt interpretowany jest plikiem  tekstowym  mającym  ustawione  prawo  do  wykonywania.
       Pierwsza linia tego pliku jest w postaci:

           #! interpreter [opcjonalny-parametr]

       interpreter mus być poprawną nazwą ścieżki do pliku wykonywalnego. Jeśli argument filename
       wywołania  execve()  określa  interpreter,   to   zostanie   uruchomiony   interpreter   z
       następującymi argumentami:

           interpreter [opcjonalny-arg] filename arg...

       gdzie  arg...  jest  serią  słów,  na  które  wskazuje  argument  argv wywołania execve(),
       poczynając od argv[1].

       Dla zachowania przenośności na inne systemu optional-arg albo w  ogóle  nie  powinien  być
       podawany,  albo  powinien być podany jako pojedyncze słowo (nie powinien zawierać spacji);
       patrz UWAGI poniżej.

       Od Linuksa 2.6.28  jądro  pozwala,  aby  interpreterem  skryptu  również  był  skrypt.  To
       uprawnienie  jest  rekurencyjne,  aż po czterykroć, tak więc interpreter może być skryptem
       interpretowanym przez skrypt itd.

   Ograniczenia rozmiaru argumentów i środowiska
       Większość implementacji Uniksa narzuca ograniczenia na całkowity rozmiar argumentów  linii
       poleceń  (argv)  i  środowiska  (envp)  przekazywanych do nowego programu. POSIX.1 pozwala
       implementacji ogłosić te ograniczenia za  pomocą  stałej  ARG_MAX  (albo  zdefiniowanej  w
       <limits.h>,   albo   dostępnej   podczas   wykonywania   programu   za   pomocą  wywołania
       sysconf(_SC_ARG_MAX)).

       W jadrach Linuksa wcześniejszych niż 2.6.23, pamięć używana  do  przechowywania  łańcuchów
       znaków  środowiska  i  argumentów  była  ograniczana do 32 stron (zdefiniowane przez stałą
       jądra MAX_ARG_PAGES). W architekturach mających strony  o  rozmiarze  4  kB  oznaczało  to
       maksymalny rozmiar równy 128 kB.

       W  jądrze  2.6.23  i  późniejszych  większość  architektur  wspiera  ograniczenie rozmiaru
       wywodzące się z miękkiego limitu zasobu  RLIMIT_STACK (patrz getrlimit(2)), obowiązującego
       podczas wywołania execve() (Wyjątek stanowią architektury nie mające jednostki zarządzania
       pamięcią: przechowują ograniczenie obowiązujące przed wersją  jądra   2.6.23).  Zmiana  ta
       pozwala programom na posiadanie znacznie większej listy argumentów lub środowiska. Na tych
       architekturach całkowity rozmiar jest ograniczony do 1/4  dopuszczalnego  rozmiaru  stosu.
       (Limit   1/4  zapewnia,  że  zostanie  jakaś  przestrzeń  na stos dla nowego programu). Od
       Linuksa 2.6.25 jądro przyjmuje wartość minimalną 32 stron dla tego  limitu  rozmiaru,  tak
       żeby  zagwarantować,  że  w  przypadku  gdy  RLIMIT_STACK  ma niewielką wartość, aplikacje
       dostaną co najmniej taką przestrzeń na argumenty  i  środowisko,  jaką  miały  w  Linuksie
       2.6.23  i wcześniejszych. (Takiej gwarancji nie ma w Linuksach 2.6.23 i 2.6.24). Dodatkowo
       ograniczeniem na pojedynczy łańcuch znaków są 32 strony (stała  jądra  MAX_ARG_STRLEN),  a
       maksymalna liczba takich łańcuchów wynosi 0x7FFFFFFF.

WARTOŚĆ ZWRACANA

       Po  pomyślnym  zakończeniu  execve()  nie  wraca,  w  wypadku  błędu  zwracane  jest  -1 i
       odpowiednio ustawiane errno.

BŁĘDY

       E2BIG  Całkowita liczba bajtów środowiska (envp) i listy argumentów (argv) jest za duża.

       EACCES Brak praw do przeszukiwania dla składnika ścieżki filename lub ścieżki interpretera
              skryptu (patrz także path_resolution(7)).

       EACCES Plik lub interpreter skryptu nie jest zwykłym plikiem.

       EACCES Brak praw wykonywania dla pliku, skryptu lub intepretera ELF.

       EACCES System plików jest zamontowany jako noexec.

       EAGAIN (od Linuksa 3.1)
              Po  zmianie  swojego  rzeczywistego  UID  za  pomocą  jednego  z wywołań set*uid(),
              wywołujący był—i  wciąż  jest—powyżej  swojego  limitu  zasobó  RLIMIT_NPROC  (zob.
              setrlimit(2)). Więcej informacji o tym błędzie znajduje się w rozdziale UWAGI.

       EFAULT filename  lub  jeden ze wskaźników w wektorach argv lub envp wskazuje poza dostępną
              dla użytkownika przestrzeń adresową.

       EINVAL Plik wykonywalny w formacie ELF ma więcej niż  jeden  segment  PT_INTERP  (tzn.  ma
              więcej niż jeden interpreter).

       EIO    Wystąpił błąd wejścia-wyjścia.

       EISDIR Intepreter ELF jest katalogiem.

       ELIBBAD
              Nie został rozpoznany format interpretera ELF.

       ELOOP  Podczas  rozwiązywania  filename, nazwy skryptu lub interpretera ELF napotkano zbyt
              wiele dowiązań symbolicznych.

       ELOOP  Osiągnięto maksymalny limit rekurencji podczas intepretacji rekurencyjnego  skryptu
              (zob. pow. "Skrypty interpretowane"). Przed Linuksem 3.8 w takim wypadku występował
              błąd ENOEXEC.

       EMFILE Zostało  osiągnięte  ograniczenie  na  liczbę  otwartych  deskryptorów  plików  dla
              procesu.

       ENAMETOOLONG
              filename jest zbyt długie.

       ENFILE Zostało osiągnięte systemowe ograniczenie na całkowitą liczbę otwartych plików.

       ENOENT Plik  filename,  skrypt,  lub  intepreter  ELF  nie istnieje albo nie można znaleźć
              biblioteki współdzielonej potrzebnej do uruchomienia pliku lub interpretera.

       ENOEXEC
              Nie rozpoznano formatu pliku  binarnego,  plik  ten  jest  skompilowany  dla  innej
              architektury  albo  wystąpił  jakiś  inny  błąd  formatu  pliku, który powoduje, że
              program nie może być uruchomiony.

       ENOMEM Brak dostępnej pamięci jądra.

       ENOTDIR
              Składnik ścieżki filename, ścieżki skryptu lub ścieżki interpretera  ELF  nie  jest
              katalogiem.

       EPERM  System  plików jest zamontowany jako nosuid, użytkownik nie jest administratorem, a
              plik ma ustawiony bit set-user-ID lub set-group-ID.

       EPERM  Proces jest śledzony (trace), użytkownik nie jest  superużytkownikiem,  a  plik  ma
              ustawiony bit set-user-ID lub set-group-ID.

       EPERM  Aplikację ślepe na przywileje nie pozyskają pełnego zestawu dozwolonych przywilejów
              przyznanego przez plik wykonywalny. Zob. capabilities(7).

       ETXTBSY
              Podany plik wykonywalny był otwarty do zapisu przez jeden lub więcej procesów.

ZGODNE Z

       POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.  POSIX nie opisuje zachowania #!, lecz  istnieje
       ono (z pewnymi odmianami) na innych systemach Uniksowych.

UWAGI

       Procesy  z  ustawionymi znacznikami set-user-ID oraz set-group-ID nie mogą być śledzone za
       pomocą ptrace(2).

       Efekt zamontowania systemu plików nosuid jest różny  dla  różnych  wersji  jądra  Linuksa:
       niektóre  odmówią  uruchomienia programów set-user-ID i set-group-ID, gdy spowodowałoby to
       udostępnienie użytkownikowi możliwości, którymi w danym momencie nie dysponuje  (i  zwrócą
       EPERM),  inne  po  prostu  zignorują  bity set-user-ID i set-group-ID i pomyślnie wykonają
       exec().

       Pod Linuksem argv i envp może być podany jako NULL. W  obu  przypadkach,  ma  to  ten  sam
       skutek  co  podanie  danego  argumentu  jako  wskaźnika  do  listy zawierającej pojedynczy
       wskaźnik  null.  Prosimy   nie   wykorzystywać   tej   niestandardowej   i   nieprzenośnej
       pseudofunkcji!  Na  większości  innych systemów Uniksowych podanie jako argv wartości NULL
       spowoduje wystąpienie błędu (EFAULT). Część innych systemów Uniksowych traktuje  przypadek
       envp==NULL tak samo jak Linux.

       POSIX.1 określa, że wartości zwracane przez sysconf(3) nie powinny się zmieniać przez cały
       czas życia procesu. Jednakże od wersji 2.6.23 Linuksa zmiana limitu  zasobów  RLIMIT_STACK
       powoduje również zmianę wartości zwracanej przez _SC_ARG_MAX, żeby odzwierciedlić fakt, że
       zmieniły się ograniczenia przestrzeni służącej do przechowywania argumentów linii  poleceń
       i zmiennych środowiska.

       W  większości  sytuacji  gdy  execve()  zawiedzie, kontrola powraca do oryginalnego obrazu
       wykonywalnego, a wywołujący execve() może następnie obsłużyć  błąd.  Jednak  są  (rzadkie)
       przypadki  (zwykle  przy  braku  zasobów),  gdy błąd może wystąpić w momencie bez powrotu:
       oryginalny obraz wykonywalne został podzielony, a nie  można  całkowicie  zbudować  nowego
       obrazu. W takich sytuacjach jądro zabija proces sygnałem SIGKILL.

   Skrypty interpretowane
       Maksymalna długość pierwszego wiersza skryptu interpretera wynosi 127 znaków.

       Semantyka  argumentu optional-arg skryptu interpretera różni się pomiędzy implementacjami.
       Pod Linuksem cały łańcuch znaków występujący po nazwie interpretera jest przekazywany jako
       pojedynczy  argument.  Jednakże  inne  systemy  zachowują  się  inaczej.  Niektóre systemy
       traktują  pierwszy  znaku  białej  spacji  jako  znak  kończący  optional-arg.  Na  innych
       systemach  skrypt interpretera może przyjmować wiele argumentów i białe znaki optional-arg
       służą do ich rozdzielania.

       Linux ignoruje bity set-user-ID i set-group-ID dla skryptów.

   execve() i EAGAIN
       Poniżej znajduje się bardziej szczegółowy opis  błędu  EAGAIN,  który  może  wystąpić  (od
       Linuksa 3.1) przy wywoływaniu execve().

       Błąd  EAGAIN  może  wystąpić,  gdy  wywołanie  poprzedzające  setuid(2),  setreuid(2)  lub
       setresuid(2) spowodowało, że rzeczywisty ID użytkownika procesu zmienił się  i  ta  zmiana
       doprowadziła  do  wyczerpania  jego  limitu  zasobów  RLIMIT_NPROC  (tzn.  liczba procesów
       należących do nowego rzeczywistego UID przekroczy limit zasobów). W  wersjach  Linuksa  od
       2.6.0  do  3.0  powodowało  to  niepowodzenie  wywołania set*uid(). Przed wersja 2.6 limit
       zasobów  nie  był nakładany  w  przypadku  procesów   zmieniających   swój   identyfikator
       użytkownika.

       Od  Linuksa  3.1,  opisana  sytuacja  nie  powoduje już niepowodzenia wywołania set*uid(),
       ponieważ zbyt często prowadziło to do dziur  bezpieczeństwa,  gdy  nieprawidłowo  napisane
       programy  nie  sprawdzały  statusu  zakończenia  i  przyjmowały,  że—jeśli  wywołujący  ma
       uprawnienia roota—wywołanie zawsze powiedzie się. Obecnie  wywołania  set*uid()  poprawnie
       zmieniają   rzeczywisty  UID,  lecz  jądro  ustawia  wewnętrzną  flagę  PF_NPROC_EXCEEDED,
       wskazując że przekroczono limit zasobów RLIMIT_NPROC. Jeśli flaga  PF_NPROC_EXCEEDED  jest
       ustawiona, a limit zasobów jest wciąż przekroczony w trakcie kolejnego wywołania execve(),
       to wywołanie to zakończy się z błędem EAGAIN.  Ta logika jądra zapewnia, że limit  zasobów
       RLIMIT_NPROC  jest wciąż wymuszony dla zwykłej pracy demonów uprzywilejowanych —przykładem
       jest fork(2)  + set*uid()  + execve().

       Jeśli jednak limit zasobów nie był już przekroczony w trakcie wywołania execve() (ponieważ
       zakończyły  się  inne  procesy  należące  do  tego  rzeczywistego UID pomiędzy wywołaniami
       set*uid() i execve()), to wywołanie execve() powiedzie się, a jądro usunie  flagę  procesu
       PF_NPROC_EXCEEDED.  Flaga  jest  usuwana również wówczas, gdy kolejne wywołanie do fork(2)
       przez ten proces powiedzie się.

   Historia
       W Uniksie V6 lista  argumentów  wywołania  exec()  była  kończona  0,  podczas  gdy  lista
       argumentów  funkcji main była kończona -1. Dlatego lista argumentów przekazana do main nie
       mogła być bezpośrednio użyta w wywołaniu exec(). Od Uniksa V7 obie te wartości są NULL.

PRZYKŁAD

       Następujący program jest zaprojektowany do wykonania  przez  drugi  program  przedstawiony
       poniżej. Wyświetla swoje argumenty uruchomienia po jednym w wierszu.

           /* myecho.c */

           #include <stdio.h>
           #include <stdlib.h>

           int
           main(int argc, char *argv[])
           {
               int j;

               for (j = 0; j < argc; j++)
                   printf("argv[%d]: %s\n", j, argv[j]);

               exit(EXIT_SUCCESS);
           }

       Tego programu można użyć do uruchomienia programu podanego w argumencie linii poleceń:

           /* execve.c */

           #include <stdio.h>
           #include <stdlib.h>
           #include <unistd.h>

           int
           main(int argc, char *argv[])
           {
               char *newargv[] = { NULL, "witaj", "świecie", NULL };
               char *newenviron[] = { NULL };

               if (argc != 2) {
                   fprintf(stderr, "Użycie: %s <plik-do-uruchomienia>\n", argv[0]);
                   exit(EXIT_FAILURE);
               }

               newargv[0] = argv[1];

               execve(argv[1], newargv, newenviron);
               perror("execve");   /* execve() wraca tylko w przypadku błędu */
               exit(EXIT_FAILURE);
           }

       Możemy użyć drugiego programu do uruchomienia pierwszego:

           $ cc myecho.c -o myecho
           $ cc execve.c -o execve
           $ ./execve ./myecho
           argv[0]: ./myecho
           argv[1]: witaj
           argv[2]: świecie

       Możemy  także  użyć  tych  programów  do  pokazania  używania interpretera skryptu. Aby to
       zrobić, tworzymy skrypt, którego "interpreterem"  jest nasz program myecho:

           $ cat > script
           #!./myecho script-arg
           ^D
           $ chmod +x script

       Następnie używamy naszego programu do wykonania skryptu:

           $ ./execve ./script
           argv[0]: ./myecho
           argv[1]: script-arg
           argv[2]: ./script
           argv[3]: witaj
           argv[4]: świecie

ZOBACZ TAKŻE

       chmod(2), execveat(2), fork(2), ptrace(2),  execl(3),  fexecve(3),  getopt(3),  system(3),
       credentials(7), environ(7), path_resolution(7), ld.so(8)

O STRONIE

       Angielska  wersja  tej  strony  pochodzi  z  wydania  4.07  projektu Linux man-pages. Opis
       projektu, informacje dotyczące zgłaszania błędów, oraz najnowszą  wersję  oryginału  można
       znaleźć pod adresem https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE

       Autorami  polskiego  tłumaczenia niniejszej strony podręcznika man są: Przemek Borys (PTM)
       <pborys@dione.ids.pl>, Andrzej Krzysztofowicz (PTM) <ankry@mif.pg.gda.pl>, Robert  Luberda
       <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>.

       Polskie  tłumaczenie jest częścią projektu manpages-pl; uwagi, pomoc, zgłaszanie błędów na
       stronie  http://sourceforge.net/projects/manpages-pl/.  Jest   zgodne   z   wersją    4.07
       oryginału.