Na základě vlastní potřeby a vyburcován dopisy v linux@linux.cz jsem se rozhodl vytvořit malý seriál o tomto souborovém systému. Pro začátek bych se rád ponořil do obsahu jeho mnoha podadresářů a souborů a pro sebe i pro vás se pokusil zjistit, co všechna ta čísla vlastně znamenají. Možná to bude trochu připomínat detektivní pátrání, ale věřím, že s pomocí Webu, zdrojového kódu Linuxu a grepu se mi podaří shromáždit spoustu zajímavých informací.
Pokud bude zájem, mohl bych též připojit jeden díl o programování modulů pro jádro, které vytváří položky v adresáři /proc. Možná by neškodilo i malé zamyšlení nad přenositelností programů využívajících tyto informace a knihovny typu libproc.
Takže vzhůru do pátrání. Nejprve malý úvod pro ty, kteří nemají úplně jasno v tom, co to ten /proc je. Jedná se o virtuální souborový systém připojovaný do adresáře /proc. K připojení se použije klasický příkaz mount, například takto:
mount -t proc proc /proc
Na první pohled je podivné, co je to za speciální soubor v druhém parametru. Odpověď je (překvapivě) zcela prostá. Žádné zařízení proc neexistuje a v zápise je použito pouze pro zachování stejné syntaxe s ostatními druhy souborových systémů. Vše, co je třeba, pozná mount podle typu. Ten je v tomto případě proc. Pokud jste se někdy vrtali v jádře, víte, že operace nad souborovými systémy (jakož i nad spoustou jiných věcí) jsou realizovány přes popisnou strukturu daného zařízení. Ta obsahuje ukazatele na funkce pro všechny možné operace. Pokud tedy například provedeme otevření souboru v systému, kde je Ext2, použije se ukazatel na funkci „open“, který je pro systém Ext2 nastaven na funkci řekněme „ext2_open“. Ta schroustá data z disku (respektive z cache) a vrátí je uživateli. Pokud je ale daným systémem souborů /proc, má nastavenu funkci, která data vygeneruje z informací v jádře. A uživatel nic nepozná, pracuje se soubory úplně stejně. Zápis probíhá obdobně, až na to, že zapisovaná data se nikam neukládají, ale použijí se k nastavení parametrů jádra.
Teď už máme představu, jak souborový systém proc funguje, takže vzhůru na prozkoumávání jeho obsahu. Ten se samozřejmě bude lišit v závislosti na verzi jádra operačního systému, ale hlavně dle toho, co všechno jsme do jádra zakompilovali a/nebo jaké jsou v daném okamžiku nahrány moduly. Určitý základ ale bude stejný, zbytek bude vycházet z mého aktuálního nastavení. Pokud Vám tedy bude nějaká oblast chybět, řekněte si. Na mém počítači je nyní poslední stabilní jádro 2.4.5 (ano, jsem sebevrah :).
Nejprve se podíváme na výpis adresáře /proc:
924/ devices interrupts loadavg net/ sys/ 946/ dma iomem locks partitions sysvipc/ 968/ driver/ ioports meminfo pci tty/ apm execdomains irq/ misc self@ uptime bus/ filesystems kcore modules slabinfo version cmdline fs/ kmsg mounts stat cpuinfo ide/ ksyms mtrr swaps
Tento výpis je „poněkud“ zkrácen, adresářů pojmenovaných číslem je ve skutečnosti mnohem víc. Nyní se pojďme podívat na jednotlivé položky výpisu. V tomto dílu si jako předkrm před dalšími zajímavostmi, na jejichž pečlivější nastudování budu potřebovat trochu času, podíváme na informace o procesech. To jsou právě ony adresáře pojmenované číslem. Jak jistě uhodnete, číslo odpovídá PID procesu.
Příkladem nám bude adresář informací o procesu bash. Tento proces má PID podle následujícího výpisu programu ps -e rovno 300:
PID TTY TIME CMD ... 300 tty1 00:00:00 bash ...
Vybrali jsme proces, který jsme sami vytvořili, abychom měli patřičná přístupová práva ke čtení jeho informací. Obsah adresáře /proc/300 je potom následující:
-r--r--r-- 1 sioux users 0 Jun 16 13:07 cmdline lrwxrwxrwx 1 sioux users 0 Jun 16 13:07 cwd -> /home/sioux -r-------- 1 sioux users 0 Jun 16 13:07 environ lrwxrwxrwx 1 sioux users 0 Jun 16 13:07 exe -> /bin/bash dr-x------ 2 sioux users 0 Jun 16 13:07 fd/ -r--r--r-- 1 sioux users 0 Jun 16 13:07 maps -rw------- 1 sioux users 0 Jun 16 13:07 mem lrwxrwxrwx 1 sioux users 0 Jun 16 13:07 root -> / -r--r--r-- 1 sioux users 0 Jun 16 13:07 stat -r--r--r-- 1 sioux users 0 Jun 16 13:07 statm -r--r--r-- 1 sioux users 0 Jun 16 13:07 status
Poprvé si to ještě trochu rozpitváme, příště už se budeme zajímat především o obsah souborů. Nejprve práva. Většina je pouze pro čtení, mem, což je obraz paměti, je i zapisovatelný (ale pouze pro majitele). Nic překvapujícího, tedy dále. Vlastník souborů je určen podle aktuálního EUID a EGID procesu. Pokud tedy proces bude po dobu svého běhu nějak měnit efektivní UID nebo GID, změna se zde projeví. Velikost je u většiny položek při výpisu adresářů nulová, neboť skutečný obsah je generován až při samotném přístupu k souboru a může se tedy měnit. Časy vytvoření (ale i přístupu atd.) jsou nastaveny na dobu vygenerování záznamů.
A teď už konečně jednotlivé položky:
- cmdline
- v našem případě je obsahem „-bash“. Jedná se o stejné řetězce, jaké vidí aplikace v poli argv[]. Obsahuje tedy název aplikace a případné parametry.
- cwd
- symbolický link na aktuální pracovní adresář.
- environ
- obsahuje seznam proměnných prostředí dostupných danému procesu. Jde o nulou ukončené řetězce:
HOME=/home/sioux\0SHELL=/bin/bash\0TERM=linux\0....
Na konci je pouze nula ukončující poslední řetězec a konec seznamu je nutno rozeznávat podle konce souboru. - exe
- symbolický link na soubor, který obsahuje program pro daný proces. Zde je to: „/bin/bash“.
- fd
- Tento adresář obsahuje odkazy na použité deskriptory souborů. Jde o symbolické linky na soubory (pro příklad: „0 → /dev/tty1“).
- maps
- V jádrech řady 2.4 jsou diskové soubory jako spustitelné (binární) programy a knihovny připojovány do adresového prostoru procesu pomocí mapování příslušného souboru funkcí mmap(). Ta způsobí zobrazení obsahu souboru z disku do LAP (Logický Adresový Prostor) procesu a pokud je potom požadována stránka z této oblasti, natáhne se při ošetřování výjimky požadovaná stránka do fyzické paměti. Při uvolňování se tyto stránky (u souborů s kódem) prostě zahodí, protože je lze načíst znovu z disku. Tato položka v systému /proc obsahuje informace o takto mapovaných souborech. Každý řádek odpovídá jedné oblasti a obsahuje následující položky: rozsah použitých logických adres, práva pro danou oblast, offset v počtu stránek, hlavní a vedlejší číslo zařízení, ze kterého pochází soubor, inode příslušného souboru a nakonec jméno souboru. Pro nás je začátek souboru následující:
08048000-080c0000 r-xp 00000000 03:04 17053 /bin/bash 080c0000-080c6000 rw-p 00077000 03:04 17053 /bin/bash 080c6000-08100000 rwxp 00000000 00:00 0 40000000-40015000 r-xp 00000000 03:04 15669 /lib/ld-2.2.so 40015000-40016000 rw-p 00014000 03:04 15669 /lib/ld-2.2.so ....
Je vidět i díra v LAP, dále je patrné, že kód a statická data jsou mapována zvlášť kvůli přístupovým právům. Přístupové právo ‚p‘ značí „private“, opakem je ‚s‘ pro „shared“. - mem
- Zpřístupňuje logický adresový prostor procesu. Bohužel se mi tento soubor nepodařilo přečíst. Při čtení to vždy hlásilo chybu:
se710.root /proc/277> cat ./mem cat: ./mem: Tento proces neexistuje
Pokud zjistím, v čem byl problém, dodělám errata. - root
- symbolický link na kořenový adresář pro daný proces. Většinou je to „/“, pouze pro chrootované programy je hodnota jiná.
- stat
- obsahuje informace o procesu. Stejné informace, ale v čitelnější podobě, přináší soubor status
- statm
- Informace o stavu paměti využívané procesem. Jednotlivé čísla mají následující význam: velikost programu, počet stránek celkem, počet sdílených stránek, počet stránek kódu, počet stránek dat a zásobníku, počet stránek knihoven, počet modifikovaných stránek. Všechny počty stránek se vztahují k aktuálnímu obsahu fyzické paměti pro daný proces. V našem případě je obsah:
"89 1 1 0 0 1 0"
- status
- Zde lze najít následující informace o procesu (a opět ukázka našeho procesu 300):
Name: bash State: S (sleeping) Pid: 300 PPid: 294 TracerPid: 0 Uid: 500 500 500 500 Gid: 100 100 100 100 FDSize: 256 Groups: 100 VmSize: 2432 kB VmLck: 0 kB VmRSS: 0 kB VmData: 260 kB VmStk: 24 kB VmExe: 480 kB VmLib: 1412 kB SigPnd: 0000000000000000 SigBlk: 0000000000010000 SigIgn: 0000000000384004 SigCgt: 000000004b813efb CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000
Položky jméno, stav, PID, PPID (Parent PID) jsou snad jasné. Jenom připomenu, že možné hodnoty stavu jsou: R(running), S(sleeping), D(disk sleep), Z(zombie), T(stoped), W(paging). Takže co ten zbytek.
TracerPID: dle zdrojového kódu jádra nastaven napevno na hodnotu ‚0‘.
Uid: pole obsahuje postupně UID, EUID, SUID, FSUID
Gid: pole obsahuje postupně GID, EGID, SGID, FSGID
FDSize: velikost tabulky deskriptorů souborů
Groups: seznam skupin do nichž proces patří
VmSize: Obsazený LAP
VmLck: Velikost uzamčené paměti (LAP i FAP)
VmRSS: Velikost přiděleného FAP (RAM)
VmData: Velikost datových stránek
VmStk: Velikost zásobníku
VmExe: Velikost kódu programu
VmLib: Velikost paměti pro kód knihoven
SigPnd: maska signálů doručených během blokování
SigBlk: aktuální maska blokovaných signálů
SigIgn: aktuální maska ignorovaných signálů
SigCgt: aktuální maska obsluhovaných signálů (aplikací)
CapInh,Prm,Eff: zděděné, nastavené a efektivní vlastnosti procesu. Obsluhuje některá (především bezpečnostní) nastavení procesu dle normy POSIX. Příkladem budiž CAP_CHOWN, což je příznak povolující nebo zakazující změnu vlastníka. (detaily – norma POSIX)
Tak a to je pro dnešek vše. Očekávám vaše připomínky, názory a komentáře v diskusi k článku. Ve výpisu adresáře /proc v tomto článku vidíte, co bude postupně obsahem dalších dílů.