syscalls - linuksowe wywołania systemowe
Linuksowe wywołania systemowe.
Wywołanie systemowe jest podstawowym interfejsem
pomiędzy aplikacją a jądrem Linux.
Wywołania systemowe i biblioteczne funkcje
opakowujące
Wywołania systemowe nie są zwykle wywoływane
bezpośrednio, lecz za pośrednictwem funkcji
opakowujących glibc (lub jakiejś innej biblioteki).
Szczegóły na temat bezpośredniego przywoływania
wywołań systemowych opisano w podręczniku
intro(2). Często, lecz nie zawsze, nazwa funkcji
opakowującej jest taka sama, jak przywoływanego przez
nią wywołania systemowego. Przykładowo glibc zawiera
funkcję chdir() przywołującą
wywołanie systemowe „chdir”.
Funkcja opakowująca glibc jest często skromna, nie
robiąc wiele poza skopiowaniem argumentów do
prawidłowych rejestrów przed wywołaniem
wywołania systemowego, a potem ustawiając odpowiednio
errno po powrocie wywołania systemowego (te same kroki
są wykonywane przez syscall(2), które może
służyć do przywoływania wywołań
systemowych, które nie posiadają funkcji
opakowujących). Uwaga: wywołanie systemowe zgłasza
niepowodzenie, zwracając ujemny numer błędu do
wywołującego, na architekturach które nie
posiadają odrębnej flagi/rejestru błędów,
jak to opisano w syscall(2); gdy tak się stanie, funkcja
opakowująca zmienia znak zwracanego numeru błędu (staje
się on dodatni), kopiuje go do errno i zwraca -1 do
wywołującego funkcję opakowującą.
Czasem jednak, funkcja opakowująca wykonuje
dodatkową pracę przed przywołaniem wywołania
systemowego. Na przykład, istnieją obecnie (z powodów
opisanych niżej) dwa spokrewnione wywołania systemowe:
truncate(2) i truncate64(2), a funkcja opakowująca
glibc truncate() sprawdza, które z nich jest zapewnione przez
jądro i określa, którego należy
użyć.
Poniżej przedstawiono listę linuksowych
wywołań systemowych. Kolumna Jądro wskazuje
wersję jądra w przypadku wywołań, które
pojawiły się w Linuksie 2.2 lub później.
Proszę odnotować, że:
- •
- Jeśli nie wskazano wersji jądra, wywołanie systemowe
pojawiło się w Linuksie 1.0 lub wcześniej.
- •
- Jeśli wywołanie systemowe oznaczono wersją
„1.2” oznacza to, że wywołanie systemowe
prawdopodobnie pojawiło się w wersji jądra Linux
1.1.x, czyli pierwszą wersją stabilną z danym
wywołaniem była wersja 1.2 (rozwój Linuksa 1.2
rozpoczął się od odgałęzienia od wersji
1.0.6 Linuksa i trwał w ramach niestabilnej serii jąder
Linux 1.1.x).
- •
- Jeśli wywołanie systemowe oznaczono wersją
„2.0” oznacza to, że wywołanie systemowe
prawdopodobnie pojawiło się w wersji jądra Linux
1.3.x, czyli pierwszą wersją stabilną z danym
wywołaniem była wersja 2.0 (rozwój Linuksa 2.0
rozpoczął się od odgałęzienia od wersji
1.2.x, gdzieś w okolicach wersji 1.2.10 Linuksa, i trwał w
ramach niestabilnej serii jąder Linux 1.3.x).
- •
- Jeśli wywołanie systemowe oznaczono wersją
„2.2” oznacza to, że wywołanie systemowe
prawdopodobnie pojawiło się w wersji jądra Linux
2.1.x, czyli pierwszą wersją stabilną z danym
wywołaniem była wersja 2.2.0 (rozwój Linuksa 2.2
rozpoczął się od odgałęzienia od wersji
2.0.21 Linuksa i trwał w ramach niestabilnej serii jąder
Linux 2.1.x).
- •
- Jeśli wywołanie systemowe oznaczono wersją
„2.4” oznacza to, że wywołanie systemowe
prawdopodobnie pojawiło się w wersji jądra Linux
2.3.x, czyli pierwszą wersją stabilną z danym
wywołaniem była wersja 2.4.0 (rozwój Linuksa 2.4
rozpoczął się od odgałęzienia od wersji
2.2.8 Linuksa i trwał w ramach niestabilnej serii jąder
Linux 2.3.x).
- •
- Jeśli wywołanie systemowe oznaczono wersją
„2.6” oznacza to, że wywołanie systemowe
prawdopodobnie pojawiło się w wersji jądra Linux
2.5.x, czyli pierwszą wersją stabilną z danym
wywołaniem była wersja 2.6.0 (rozwój Linuksa 2.6
rozpoczął się od odgałęzienia od wersji
2.4.15 Linuksa i trwał w ramach niestabilnej serii jąder
Linux 2.5.x).
- •
- Od wersji Linuksa 2.6.0, model rozwoju zmienił się, a nowe
wywołania systemowe mogą pojawiać się w
każdym wydaniu Linuksa 2.6.x. W takim przypadku podana jest
dokładna wersja, w której pojawiło się dane
wywołanie systemowe. Tę konwencję stosuje się
również: w serii jąder Linux 3.x, która
rozpoczęła się po Linuksie 2.6.39; w serii
jąder Linux 4.x, która rozpoczęła się
po Linuksie 3.19; w serii jąder Linux 5.x, która
rozpoczęła się po Linuksie 4.20; w serii jąder
Linux 6.x, która rozpoczęła się po Linuksie
5.19.
- •
- W niektórych sytuacjach, wywołanie systemowe dodano do
stabilnej serii jąder po jej odgałęzieniu z
poprzedniej stabilnej serii jąder, a następnie przeportowano
do wcześniejszej stabilnej serii jąder. Na przykład
część wywołań systemowych, które
pojawiły się w Linuksie 2.6.x przeportowano
również do wydania Linux 2.4.x po Linuksie 2.4.15. W takim
przypadku, podane są wersje z obu głównych serii
jąder, w których pojawiło się dane
wywołanie.
Lista wywołań systemowych dostępnych w
Linuksie 5.14 (w kilku przypadkach tylko na starszych jądrach) jest
następująca:
Na wielu platformach, w tym x86-32, wywołania gniazd
są zwielokrotniane (za pomocą funkcji opakowujących
glibc) poprzez socketcall(2) i analogicznie wywołania IPC
Systemu V są zwielokrotniane poprzez ipc(2).
Dla następujących wywołań systemowych
zarezerwowano miejsca w systemowej tablicy wywołań, ale nie
są one zaimplementowane w standardowym jądrze:
afs_syscall(2), break(2), ftime(2), getpmsg(2),
gtty(2), idle(2), lock(2), madvise1(2),
mpx(2), phys(2), prof(2), profil(2),
putpmsg(2), security(2), stty(2), tuxcall(2),
ulimit(2) i vserver(2) (zob. też
unimplemented(2)). Jednak ftime(3), profil(3) i
ulimit(3) istnieją jako funkcje biblioteczne. Miejsce dla
phys(2) od Linuksa 2.1.116 jest używane przez
umount(2); phys(2) nigdy nie zostanie zaimplementowane.
Wywołania getpmsg(2) i putpmsg(2) są
przeznaczone do jąder zmodyfikowanych do obsługi struktury
STREAMS i mogą nigdy nie trafić do standardowego
jądra.
Istniało przez chwilę set_zone_reclaim(2),
dodane w Linuksie 2.6.13 i usunięte w Linuksie 2.6.16; to
wywołanie systemowe nigdy nie było dostępne dla
przestrzeni użytkownika.
Najczęściej kod należący do
wywołania systemowego o numerze __NR_xxx zdefiniowanym w
/usr/include/asm/unistd.h można znaleźć w
źródłach jądra Linux w funkcji sys_xxx().
Istnieje jednak wiele wyjątków, głównie z powodu
zastąpienia starszych wywołań systemowych nowszymi, co
odbyło się w nie do końca systematyczny sposób.
Na platformach z zastrzeżoną emulacją systemu
operacyjnego, takich jak sparc, sparc64 i alpha, istnieje wiele dodatkowych
wywołań systemowych; mips64 zawiera również
pełny zbiór 32-bitowych wywołań systemowych.
Z czasem, konieczna była zmiana interfejsów
niektórych wywołań systemowych. Jedną z przyczyn
była konieczność zwiększenia struktur
wartości skalarnych przekazywanych do wywołań
systemowych. Z powodów tych zmian, niektóre architektury
(między innymi długowieczne architektury 32-bitowe, takie jak
i386) mają obecnie grupy powiązanych wywołań
systemowych (np. truncate(2) i truncate64(2))
realizujących podobne zadania, lecz różniących
się w szczegółach, takich jak rozmiar swoich
argumentów (jak zaznaczono wcześniej, aplikacje zwykle nie
są tego świadome; funkcje opakowujące glibc
wykonują pewną pracę, aby przywołać
odpowiednie wywołanie systemowe oraz zapewnić
kompatybilność ABI dla starszych plików wykonywalnych).
Oto przykłady wywołań systemowych, które
istnieją w różnych wersjach:
- •
- Obecnie występują trzy różne wersje
stat(2): sys_stat() (miejsce __NR_oldstat),
sys_newstat() (miejsce __NR_stat) i sys_stat64()
(miejsce __NR_stat64), z których ostatnia jest najnowsza.
Podobna sytuacja występuje w przypadku lstat(2) i
fstat(2).
- •
- Podobnie, definicje __NR_oldolduname, __NR_olduname i
__NR_uname odnoszą się do funkcji
sys_olduname(), sys_uname() i sys_newuname().
- •
- W Linuksie 2.0, pojawiła się nowa wersja vm86(2),
przy czym stara i nowa funkcja otrzymała nazwę, odpowiednio,
sys_vm86old() i sys_vm86().
- •
- W Linuksie 2.4, pojawiła się nowa wersja
getrlimit(2), przy czym stara i nowa funkcja otrzymała
nazwę, odpowiednio, sys_old_getrlimit() (miejsce
__NR_getrlimit) i sys_getrlimit() (miejsce
__NR_ugetrlimit).
- •
- Linux 2.4 zwiększył rozmiar identyfikatorów
użytkownika i grupy z 16 do 32 bitów. Aby
obsłużyć tę zmianę, dodano wiele
wywołań systemowych (np. chown32(2),
getuid32(2), getgroups32(2), setresuid32(2)),
zastępujących wcześniejsze wywołania o tej
samej nazwie, bez przyrostka „32”.
- •
- Linux 2.4 dodał obsługę dostępu do
dużych plików dla aplikacji 32-bitowych (tj. plików,
których rozmiaru i przesunięcia pliku nie da się
odwzorować w 32 bitach). Aby obsłużyć
tę zmianę, konieczne było zastąpienie
wywołań systemowych, które działają na
przesunięciach plików i ich rozmiarach. Z tego
względu dodano wywołania systemowe: fcntl64(2),
getdents64(2), stat64(2), statfs64(2),
truncate64(2) oraz ich odpowiedniki działające na
deskryptorach plików i dowiązaniach symbolicznych. Opisywane
wywołania zastąpiły starsze wywołania
systemowe, które, z wyłączeniem wywołań
„stat”, miały te same nazwy, jedynie bez przyrostka
„64”.
- Na nowszych platformach, które mają jedynie 64-bitowy
dostęp do plików i 32-bitowe identyfikatory
użytkownika i grupy (np. alpha, ia64, s390x, x86-64), istnieje
jedynie pojedyncza wersja wywołań systemowych
związanych z UID-ami, GID-ami i dostępem do plików.
Na platformach (zwykle 32-bitowych), gdzie istnieją
wywołania *64 i *32, pozostałe wersje są
przestarzałe.
- •
- Wywołania rt_sig* dodano w Linuksie 2.2 w celu
obsługi sygnałów czasu rzeczywistego (zob.
signal(7)). Te wywołania systemowe zastąpiły
starsze wywołania o tej samej nazwie, jedynie bez przedrostka
„rt_”.
- •
- Wywołania systemowe select(2) i mmap(2)
używają pięciu lub więcej argumentów,
co powodowało problemy, ze względu na sposób, w jaki
zorganizowano przekazywanie argumentów na i386. Z tego
względu, choć inne architektury mają
sys_select() i sys_mmap() odpowiadające
__NR_select i __NR_mmap, ma i386 można
znaleźć w tym miejscu old_select() i
old_mmap() (funkcje korzystające z wskaźnika do bloku
argumentów). Obecnie przekazywanie pięciu argumentów
nie jest już problemem, dlatego występuje
__NR__newselect, które odpowiada bezpośrednio
sys_select() i podobnie __NR_mmap2. s390x jest jedyną
architekturą 64-bitową, która posiada
old_mmap().
- getxgid(2)
- zwraca parę: identyfikator grupy i efektywny identyfikator grupy za
pomocą rejestrów r0 i r20; zapewnione w zamian
za getgid(2) i getegid(2).
- getxpid(2)
- zwraca parę: identyfikator procesu i efektywny identyfikator
procesu za pomocą rejestrów r0 i r20;
zapewnione w zamian za getpid(2) i getppid(2).
- old_adjtimex(2)
- jest wariantem adjtimex(2) używającym struct
timeval32, ze względu na kompatybilność z
OSF/1.
- getxuid(2)
- zwraca parę: identyfikator użytkownika i efektywny
identyfikator użytkownika za pomocą rejestrów
r0 i r20; zapewnione w zamian za getuid(2) i
geteuid(2).
- sethae(2)
- służy do konfiguracji rejestru Host Address Extension na
tanich komputerach Alpha, w celu uzyskania dostępu do przestrzeni
adresowej poza pierwszymi 27 bitami.
Tłumaczenie niniejszej strony podręcznika:
Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną
dokumentacją. Bliższe informacje o warunkach licencji
można uzyskać zapoznając się z
GNU General
Public License w wersji 3 lub nowszej. Nie przyjmuje się
ŻADNEJ ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika
prosimy zgłaszać na adres listy dyskusyjnej
manpages-pl-list@lists.sourceforge.net.