UNIX 4. Soubory a proudy © Milan Keršlágerhttp:// Obsah: ● soubor, přípona, speciální soubory, adresář, cesta ● pracovní adresář, uchovávané časy (atime, mtime, ctime) ● standardní adresářová struktura unixových systémů ● pevný odkaz, symbolický odkaz ● systémová volání pro práci se soubory ● mazání otevřených souborů, důsledky ● standardní proudy, přesměrování, kolony, filtr
Soubor ● pojmenovaná posloupnost bitů ● obsah souboru bez struktury ● název jako identifikace ● pochází z roku 1952 (skupina děrných štítků) ● nese doplňující informace (metadata) ● abstraktní přístup k datům (API) ● program vytváří, otevírá, čte, zapisuje, maže, zavírá ● stejné API bez rozlišení na použitý hardware – tj. soubor se stejnou API funkcí čte na HDD, CD, flash... ● v unixových systémech je téměř vše soubor
Konvence přípon ● jménosouboru.přípona ● unixové systémy příponu nerozlišují (tj. jádro OS) – nicméně se přípona využívá při poklepání v GUI ● slouží pouze pro uživatele ● spustitelné soubory bez přípony ● konvence přípon.c → zdrojový kód v jazyce C.h → hlavičkový soubor pro jazyk C.txt → textový soubor (holý text) ● atd.
Speciální soubory ● samy o sobě neobsahují data ● jádro při manipulaci doplňuje data odjinud ● ve výpisu odlišeny položkou „typ“ ( ls -l ) ● b → blokové zařízení (block) – typicky pevný disk ● c → znakové zařízení (char) – sériový port, terminál ● zařízení soustředěna do adresáře /dev ● speciální soubor ale může být kdekoliv ● v Linuxu dnes dynamicky vytvářeny (udev)
Další speciální soubory ● jádro k nim též přistupuje jinak ● p → pojmenovaná roura (named pipe) – jednosměrná komunikace mez nepříbuznými procesy ● s → unix domain socket (IPC socket) – umožňuje obousměrnou komunikaci mezi procesy – obdoba síťové komunikace ● d → adresář – soubor, který obsahuje seznam: jméno + číslo i-uzlu – umožňuje vytvářet strom adresářů ● l → symbolický odkaz (symlink) – obsahem souboru je cesta k jinému souboru
Speciální soubory – příklady ● /dev/sda1 ● první disk v pořadí („a“), první oddíl („1“) ● /dev/null ● „černá díra“ – co se do něj zapíše, zahodí se ● /dev/zero ● při čtení vydává neomezené množství samých nul ● /dev/tty1 ● představuje terminál, čtení dává znaky z klávesnice ● zápis znaků se objeví na obrazovce
Vlastnictví souboru ● po přejmenování ● vlastnictví souboru se nezmění ● po zkopírování ● kopie patří uživateli vytvářejícímu kopii ● po přesunu ● v rámci FS se vlastnictví nemění ● při kopírování na jiný FS → aktuální uživatel ● při editaci ● nemění vlastníka, pozor na editor (záložní kopie)
Adresář ● slouží k organizaci souborů ● vytváří stromovou strukturu ● poprvé OS Multics (Denis Ritchie) – původně jen jeden kořenový adresář ● adresář × složka (v GUI) ● implementováno od počátku Unixu ● systém souborů (FS – filesystem) ● pouze jeden kořen (root filesystem) ● ostatní FS se připojují do existujících adresářů – příkazy mount a umount, lze i ve Windows ( nepoužívá se )
Označení adresářů ● tečka →. ● označuje aktuální adresář ● dvě tečky →.. ● označují nadřízený adresář ● lomítko → / ● označuje kořen stromové struktury adresářů ● v unixových systémech je vždy jen jeden – DOS a Windows více kořenů ● aktuální adresář (resp. pracovní adresář) ● vlastnost běžícího procesu (v shellu příkaz pwd )
Cesta k souboru (path) ● adresáře odděleny znakem „/“ (lomítko) ● tento znak není přípustný ve jméně souboru 1) absolutní cesta ● začíná vždy znakem lomítka (kořen) ● /etc/fstab /etc/passwd /home 2) relativní cesta ● začíná jiným znakem, než lomítko ● fstab./fstab../etc/fstab ● vztahuje se k aktuálnímu pracovnímu adresáři
Pracovní adresář ● vlastnost běžícího procesu ● každý proces může mít jiný ● standardně adresář, ze kterého je program spuštěn – zdědí ho od shellu (z příkazové řádky) – program si může nastavit na jiný → chdir() ● slouží k doplnění relativní cesty – použije-li se relativní cesta, doplní si ji systém sám – program může adresovat soubory relativně ● používá se běžně – při přesměrování (shell), otevírání souborů,...
Uchovávané časy 1) modify (mtime) – čas poslední změny obsahu ● u souboru čas posledního zápisu 2) access (atime) – čas posledního přístupu ● evidence posledního čtení ze souboru ● každé čtení vyprovokuje zápis (aktualizaci) ● snižuje výkon souborového systému – nižší rozlišení (např. 10 minut) – úplný zákaz může ovlivnit některé další funkce ( ) 3) change (ctime) – čas poslední změny metadat ● změna v i-node (délka, oprávnění, seznam bloků...)
Struktura adresářů ● unixové systémy zachovávají jistý řád ● ale i ten se časem vyvíjel, např: – adresář /etc byl původně na vše možné, ale dnes jsou v něm výhradně konfigurační soubory – nově přibyly /opt, /media, /selinux apod. – každý systém má své „odchylky“ ● podobnost uspořádání v různých unixových OS usnadňuje orientaci správcům i uživatelům ● standard FHS (Filesystem Hierarchy Standard) – pro Linux jako FSSTND (1994) – jako FHS od roku 1996 zahrnuje BSD systémy
Struktura adresářů – 1. ● /bin – základní nástroje ● /dev – speciální soubory (zařízení) ● /etc – konfigurační soubory ● /home – domácí adresáře ● /lib – knihovny ● /root – domácí adresář správce počítače ● /sbin – nástroje pro správu počítače ● /tmp – sdílený dočasný adresář ● /usr – uživatelské programy (obsah podobný kořeni) ● /var – měnící se data (logy, databáze,...)
Struktura adresářů – 2. ● /boot – zavaděč systému + jádro OS ● soubory vmlinuz a initrd.img (jádro + ovladače) ● podadresář /boot/grub → zavaděč (GRUB) – protože celý zavaděč se do MBR (512B) nevejde ● /lost+found – ztracené (a nalezené) soubory ● pokud je smazáno jméno v adresáři, ale data zůstanou na disku alokována, dá je sem fsck ● fsck je obdoba chkdsk.exe ve Windows ● /opt – uživatelské programy (např. mimo distribuci)
Struktura adresářů – 3. ● /mnt – přípojné místo pro dočasné FS ● dříve používáno pro CD/DVD apod. ● /media – přípojné místo pro hot-plug média ● novinka, zde se připojují USB flash, CD/DVD apod. ● vytváří se automaticky podadresáře podle jmenovky ● /proc – virtuální FS ● zde jádro zveřejňuje své interní datové struktury ● vše je v podobě souborů a adresářů ● /proc/cpuinfo, /proc/partitions, atd.
Struktura adresářů – 4. ● /sys – obdoba /proc pro zařízení ● hierarchická struktura kopíruje jejich HW obdobu ● umožňuje číst (i měnit) nastavení zařízení ● /selinux – data SELinuxu ● též virtuální FS, jako je /proc ● /usr/local – obdoba kořenového adresáře ● místně specifické programy, data atd. ● typicky pro věci, které si uživatel doplnil sám ● podadresáře: bin, etc, games, include, lib, sbin...
Pevný odkaz ● pevná linka, anglicky hardlink ● další název pro soubor (nelze pro adresář) ● na jedny data může ukazovat více jmen souborů – linky mají stejné číslo i-nodu – nepřekročí hranici systému souborů ● nelze odlišit „původní název“ ● zvýší počet odkazů na soubor → +1 ● při smazání data uvolněna, až počet odkazů = 0 ● vzniká příkazem ln ln cesta [názevlinky]
Použití pevného odkazu ● výhody ● nezabere žádné místo pro data ● je to jen další položka v adresáři – adresář se alokuje po alokačních jednotkách (např. 4kiB) ● nevýhody ● nepřekročí hranici souborového systému – na každém FS se i-nody počítají vždy znovu od 0 (nuly) ● podpora pevných odkazů též ve Windows NT ● původně kvůli kompatibilitě se standardem POSIX
Příklady použití ● oprávnění zůstávají nezměněna ● název linky odkazuje na původní metadata ● potíže při vyhledávání ● ve výpisu je počet odkazů na soubor > 1 – tj. tento název není jediný, který na data odkazuje ● vyhledat ostatní znamená projít celý FS (oddíl) – nejprve zjistíme číslo i-uzlu: ls -li – pak prohledat celý příslušný souborový systém – df (zjistím, na jakém FS je soubor a kde je jeho kořen) – find kořenFS -inum číslo_i-uzlu
Symbolický odkaz ● symbolická linka, anglicky symlink, softlink ● další název pro soubor nebo adresář ● ve skutečnosti malý soubor ● obsahuje cestu k cílovému souboru – cesta může být absolutní i relativní (lepší) – vyhodnocení oprávnění podle cílového souboru ● smazání linky neovlivní cílový soubor ● smazáním cíle „trčí do prázdna“ ● vzniká příkazem ln ● ln -s cesta [názevlinky]
Použití symbolického odkazu ● výhody ● není omezeno na FS (též do síťového FS) ● nevýhody ● každá zabere místo pro 1 malý soubor ● používají se velmi často ● pokud je relativní, je funkční i po připojení do jiného adresáře – to však dnešní distribuce často ignorují ● používá se na systém alternativ ( man alternatives ) ● /etc/alternatives/java -> /usr/lib/jvm/jre openjdk.x86_64/bin/java
Příklady použití ● zkrácení cesty do oblíbeného adresáře ● uživatel provede ve svém domácím adresáři: ● ln -s /var/www/html web ● symlinky ve Windows ● vlastnost NTFS od Windows Vista ● český název Hudba je symlink do adresáře Music ● český název Dokumenty je symlink do Documents ● při smazání symbolického odkazu: ● smaže se jen symlink, cíl zůstane nezměněn ● oprávnění určují oprávnění cíle symlinky
Proudy
Soubory a proudy ● již víme, co je soubor a adresář ● vzniká otázka, jak se s nimi pracuje ● programátor (uživatel) zná název (+cestu) ● jádro OS neumí dobře pracovat se jmény ● souborový deskriptor ● abstraktní klíč → definuje POSIX ● pro jazyk C → file handle ● malé celé číslo (0, 1, 2, 3, …) – index do tabulky otevřených souborů
Práce se souborem ● systémová volání jádra operačního systému ● řekneme jméno a požadovanou operaci ● získáme souborový deskriptor ● dále již používáme jen deskriptor ● ukončíme práci s deskriptorem → uvolnění ● knihovní funkce (jazyk C) ● základní nízkoúrovňové operace – fopen, fclose, fread, fwrite,... ● interně používají systémové volání ● vracejí strukturu FILE → datový proud (stream)
open() ● systémové volání pro otevření souboru ● int open (const char *cesta, int flag,...); ● příznaky: ● O_RDONLY → jen pro čtení ● O_WRONLY → jen pro zápis ● O_RDWR → pro čtení i zápis ● doplňující parametry: ● O_APPEND (jen přidávání), O_CREAT (vytvoření), O_TRUNC (vymazání dat), O_EXCL (chyba, jeli O_CREAT a existuje), O_NONBLOCK (volání selže místo zablokování, je-li bez dat)
Offset v souboru ● soubor není jako RAM ● nelze číst libovolný bajt ● čtení i zápis probíhají z určité pozice ● jádro si musí pamatovat pozici (offset) ● počítána v bajtech od začátku ● další zápis (čtení) automaticky na následující pozici ● změna pozice pouze pomocí volání lseek() ● problém s velkými soubory ● původně 32bitové číslo → 2 GiB ● moderní systémy implicitně 64bitový
Další systémová volání ● read() ● čtení z deskriptoru ● čte se do bufferu, je dán maximální počet bajtů ● write() ● zápis do deskriptoru ● zápis z bufferu, je dán maximální počet bajtů ● close() ● uzavření deskriptoru ● unlink() ● smazání zadaného názvu souboru z adresáře
Mazání otevřených souborů ● běžná praxe v unixových systémech ● název je jen položka v adresáři (+ odkaz na i-uzel) ● i-uzel s metadaty existuje nezávisle na jménu – využíváno pro pevnou linku (hardlink) ● využíváno u dočasných souborů fd=open('/tmp/data', O_CREAT | O_EXCL); unlink('/tmp/data'); close(fd); ● soubor je založen a vzápětí smazán ● protože je otevřen, lze zapisovat i číst data v souboru – nikdo jiný ale soubor nevidí ● teprve po uzavření souboru jsou data z disku uvolněna
Důsledky odloženého mazání ● data jsou uvolněna až později ● na disku není volné místo ihned po smazání – program, ve kterém je otevřen, musí být ukončen ● aktualizace ● v paměti je stále starší verze ● kompatibilita ● v MS Windows nelze – částečně řešeno pomocí O_TEMPORARY – tento speciální příznak obsluhuje knihovna – způsobuje potíže při psaní přenositelných programů
Aktualizace (1) ● aktualizace programu ● program je spuštěn (běží) ● proběhne aktualizace souboru – starý je smazán, nový je vytvořen ● v RAM stále běží stará verze programu ● → je nutné program RESTARTOVAT – typicky démon poskytující nějakou službu ● nezbytné u bezpečnostních aktualizací ● bez restartu může program havarovat – snaží se natáhnout komponentu z disku, ale ta je novější ● lze vyzkoušet u Firefoxu ● je chyba, že si Firefox o restart sám neřekne
Aktualizace (2) ● aktualizace knihoven ● stejný problém jako v předchozím případě ● bezpečnostní aktualizace knihovny může ohrozit všechny programy, které používají starší verzi – na rozdíl od Windows jsou v Linuxu masivně sdíleny ● řešením je RESTART všech dotčených programů – při startu programu je do paměti zavedena nová verze knihoven (podle jejich názvů)
Práce s adresářem ● opendir() ● otevření adresáře a nastavení na první položku ● readdir() ● vrací přečtenou položku a posune na další položku ● closedir() ● uzavření adresáře ● rewinddir() ● nastavení na první položku v adresáři ●...
Standardní proudy ● standardní chování unixových systémů ● proces má při startu otevřeny 3 deskriptory (proudy): ● 0 – stdin → klávesnice (standardní vstup) ● 1 – stdout → terminál (standardní výstup) ● 2 – stderr → terminál (standardní chybový výstup) ● přípravu deskriptorů zajišťuje VŽDY rodič – DOS, Windows – každý program sám → nekompatibility ● chce-li program číst vstup, čte z deskriptoru 0 ● chce-li program zapsat výstup, použije 1 nebo 2 ● využívá se při přesměrování vstupu/výstupu
Původ 0, 1 a 2 ● nastavení pomocí specializovaného ioctl() ● při startu systému: 1) první je spuštěn init 2) pro konzoli spustí program getty – sdělí programu identifikaci konzole (číslo) 3) getty použije ioctl() pro připojení 0, 1 a 2 4) getty vypíše login: 5) uživatel zapíše jméno a heslo, getty je zkontroluje 6) getty se změní na shell → exec() dědí deskriptory 7) uživatel zapíše příkaz → potomek dědí deskriptory 8) po odhlášení se ukončí shell a init spustí nové getty
Vznik příkazového řádku getty() exec('/bin/bash') shell fork() wait() exec('ls') jméno + heslo ls výpis adresáře Místo getty může čekat ssh démon (přihlášení ze sítě).
Přesměrování vstupu/výstupu ● využívají se standardní proudy ● každý program používá deskriptory 0, 1 a 2 – démon je zavírá → s uživatelem nekomunikuje ● rodič pozmění cíl těchto deskriptorů – tj. shell je mění podle značek, 2>, >> atd. ● potomek dědí nastavení deskriptorů – tj. spuštěný program (např. ls, cat, grep,...) ● potomek používá pro vstup/výstup stále 0, 1 a 2 – místo na terminál pak zapisuje program do souboru – místo z klávesnice čte z předchozího procesu (kolona) – atd.
Přesměrování – BASH Příklady:ls > vystup.txt find /proc > vystup.txt 2>&1 unix2dos dos.txt
Realizace přesměrování shell fork() wait() fd = open('vypis.txt', O_CREAT); dup2(fd, stdout); close(fd); ls > vypis.txt ls výpis adresáře je do stdout, tj. do souboru vypis.txt exec('ls') write(stdout,„ahoj“)
Použití standardních proudů ● standardní deskriptory jsou výhoda ● programátor se nemusí starat (zajišťuje rodič – shell) ● využíváno v příkazovém řádku → filtry ● v GUI skryto ● na stdout zapisují aplikace ladící informace ● na stderr zapisují aplikace chybová hlášení ● typicky však zahazováno – chceme-li výstup vidět, spustíme program z přík. řádku ● Windows 7 → předávání objektů ● nutno přizpůsobit všechny dotčené programy
Kolona (roura) ● specifické využití standardních deskriptorů programA | programB – stdout z programA jde na stdin programB ● umožňuje řetězit jednoduché programy ● umožňuje postupné zpracování vstupních dat ● využívá koncept jednoúčelových nástrojů a filtrů – filtr čte vstup, pozmění ho a zapíše na výstup – nedostane-li parametr, používá 0, 1 a 2 – téměř všechny unixové nástroje se chovají jako filtry – např.: cat, grep, sort, less, awk, sed, …
Realizace kolony (roury) shell fork() wait() pipe(); grep … | sort grep... exec('grep'); fork() exec('sort'); sort roura Funkce pipe() vytváří dva nové deskriptory, které jsou propojené (zápis do jednoho se objevuje v druhém). Kód je jen naznačen.
Filtr ● je program, respektující standardní proudy ● při spuštění bez parametrů: – čte z deskriptoru 0 (tj. klávesnice) – zapisuje na 1 (stdout) a 2 (stderr) ● parametry mohou zařídit interní přesměrování: – ze souboru nebo do souboru ● filtr lze použít v koloně – kolona propojuje výstup prvního se vstupem druhého – filtr „filtruje“ (modifikuje) data → odtud název ● Příklad: cut -d: -f1 | less ● grep ro /etc/passwd | sort