Programov´an´ıv UNIXu
Jan Pechanec
verze: 17. prosince 2007
(c) 1999 – 2004 Martin Beran (c) 2005 – 2007 Jan Pechanec
SISAL MFF UK, Malostransk´en´am. 25, 118 00 Praha 1 [email protected]
Organizaˇcn´ıvˇeci: • tento pˇredmˇet je 2/1, cviˇcen´ıbude jednou za dva t´ydny v laboratoˇri UNIX • vˇsechny informace kter´ebudete potˇrebovat a materi´aly k pˇredn´aˇsce jsou na http://www.devnull.cz/mff, vˇcetnˇeaktu´aln´ıverze tˇechto pozn´amkov´ych slajd˚u • je potˇreba se zapsat na cviˇcen´ına webu • z´apoˇcet je za z´apoˇctov´yprogram • zkouˇska m´ap´ısemnou a ´ustn´ıˇc´ast, je nutn´ez´ıskat z´apoˇcet pˇred zkouˇskou, vˇcetnˇepˇredterm´ın˚u • zkouˇset se bude to, co bude odpˇredneseno (kromˇet´emat na vyplnˇen´ıpˇr´ıpadnˇe zbyl´eho ˇcasu). Vˇetˇsina informac´ıje ve slajdech, ale ˇrada d˚uleˇzit´ych podrob- nost´ım˚uˇze chybˇet. • pˇredpoklady: – uˇzivatelsk´aznalost UNIXu, programov´an´ıv shellu na ´urovni pˇredn´aˇsky ,,Uvod´ do UNIXu a TCP/IP” – znalost jazyka C – znalost z´akladn´ıch pojm˚uteorie operaˇcn´ıch syst´em˚u • tento text je pr˚ubˇeˇznˇedoplˇnov´an, ChangeLog zaˇc´ın´ana stranˇe207.
1 Obsah
• ´uvod, v´yvoj UNIXu a C, program´atorsk´en´astroje • z´akladn´ıpojmy a konvence UNIXu a jeho API • pˇr´ıstupov´apr´ava, perifern´ızaˇr´ızen´ı, syst´em soubor˚u • manipulace s procesy, spouˇstˇen´ıprogram˚u • sign´aly • synchronizace a komunikace proces˚u • s´ıt’ov´akomunikace • vl´akna, synchronizace vl´aken • ??? - bude definov´ano pozdˇeji, podle toho kolik zbyde ˇcasu
• budeme se zab´yvat hlavnˇeprincipy UNIXu a programov´an´ım pro UNIX pouze v jazyce C. • pˇredn´aˇska je pˇrev´aˇznˇeo syst´emov´ych vol´an´ıch, tj. rozhran´ım mezi uˇzivatelsk´ym prostorem a j´adrem
• pˇri popisu API se budeme drˇzet normy Single UNIX Specification, version 3. Syst´emy podporuj´ıc´ıtuto specifikaci mohou pouˇz´ıvat oznaˇcen´ıUNIX 03. V souˇcasn´edobˇe(09/2007) jsou to posledn´ıverze syst´em˚uSolaris, AIX, HP-UX a Mac OS X. • pro konkr´ern´ıpˇr´ıklady budu pouˇz´ıvat vˇetˇsinou syst´emy FreeBSD a Solaris.
2 Obsah
• ´uvod, v´yvoj UNIXu a C, program´atorsk´en´astroje • z´akladn´ıpojmy a konvence UNIXu a jeho API • pˇr´ıstupov´apr´ava, perifern´ızaˇr´ızen´ı, syst´em soubor˚u • manipulace s procesy, spouˇstˇen´ıprogram˚u • sign´aly • synchronizace a komunikace proces˚u • s´ıt’ov´akomunikace • vl´akna, synchronizace vl´aken • ??? - bude definov´ano pozdˇeji, podle toho kolik zbyde ˇcasu
Literatura v ˇceˇstinˇe
1. Skoˇcovsk´y, L.: Principy a probl´emy operaˇcn´ıho syst´emu UNIX. Science, 1993 2. Skoˇcovsk´y, Ludˇek: UNIX, POSIX, Plan9. L. Skoˇcovsk´y, Brno, 1998 3. Jelen, Milan: UNIX V - programov´an´ıv syst´emu. Grada, Praha 1993 4. Linux - Dokumentaˇcn´ıprojekt. Computer Press, 1998; http://www.cpress.cz/knihy/linux
5. Herout, Pavel: Uˇcebnice jazyka C. 2 d´ıly. Kopp, Cesk´eˇ Budˇejovice, 2004 (4., respektive 2. pˇrepracovan´evyd´an´ı)
3 OhlednˇeUnixu doporuˇcuji sp´ıˇse literaturu v anglick´em jazyce.
1. vˇsestrann´y´uvod do UNIXu, ale dost struˇcn´a; Skoˇcovsk´yje autorem v´ıce ˇcesk´ych knih o Unixu, ale dnes jsou jiˇzv´ıce nebo m´enˇezastaral´e 2. pokroˇcilejˇs´ıpohled, ale pˇredpokl´ad´apˇredbˇeˇzn´eznalosti, m´ısty tˇeˇzko stravi- teln´a 3. programov´an´ıv C pro UNIX System V, pr´ace se soubory a s procesy, System V IPC, nepopisuje napˇr. vl´akna a s´ıtˇe 4. o Linuxu bylo samozˇrejmˇev ˇceˇstinˇevyd´ano mnoho dalˇs´ıch knih 5. vynikaj´ıc´ıknihy o jazyce C
Literatura - design a principy syst´emu
1. Uresh Vahalia: UNIX Internals: The New Frontiers. Prentice Hall; 1st edition, 1995 2. Bach, Maurice J.: The Design of the UNIX Operating System. Prentice Hall, 1986 3. McKusick, M. K., Neville-Neil, G. V.: The Design and Implementation of the FreeBSD Operating System. Addison-Wesley, 2004 4. McDougall, R.; Mauro, J.: Solaris Internals. Prentice Hall; 2nd edition, 2006. 5. Linux Documentation Project. http://tldp.org/
Tyto knihy se zab´yvaj´ıstavbou Unixu, pouˇzit´ymi algoritmy, strukturami apod., nejsou to kniho o programov´an´ıpod t´ımto syst´emem.
1. skvˇel´akniha, zab´yv´ase obecn´ymi myˇslenkami UNIXu a porovn´av´asyst´emy SVR4.2, 4.4BSD, Solarix 2.x a Mach. 12/2005 mˇelo vyj´ıt druh´e, doplnˇen´e vyd´an´ı. Term´ın se vˇsak nˇekolikr´at posunul, a nyn´ı(stav k 12/2007) toto druh´e vyd´an´ıst´ale jeˇstˇenen´ık dispozici a aktu´aln´ıpl´anovan´yterm´ın je 03/2008. Tˇeˇzko ale ˇr´ıci, jestli k tomu jeˇstˇenˇekdy v˚ubec dojde. 2. klasick´akniha o UNIXu, popis struktury a funkc´ıj´adra UNIX System V Rel. 2, ˇc´asteˇcnˇei 3; pˇrestoˇze je to kniha z dneˇsn´ıho pohledu jiˇzzastaral´a, lze ji poˇr´ad jednoznaˇcnˇedoporuˇcit protoˇze to je jedna z nejlepˇs´ıch knih, co byla kdy o UNIXu naps´ana. V roce 1993 vyˇsel ˇcesk´ypˇreklad, Principy operaˇcn´ıho syst´emu UNIX, SAS.
4 3. popis struktury a funkc´ıj´adra FreeBSD 5.2; tato kniha navazuje na klasickou knihu The Design and Implementation of the 4.4 BSD Operating System od stejn´eho autora (resp. jeden ze ˇctyˇr, uveden´yjako prvn´ı) 4. nejlepˇs´ıkniha o operaˇcn´ım syst´emu Solaris. Obsahuje podrobn´einformace o tom, jak tento syst´em funguje vˇcetnˇenejnovˇejˇs´ıch vˇec´ız verze 10 jako jsou z´ony, Crypto Framework, DTrace, Least Privilege model a dalˇs´ı. 5. domovsk´astrana Linux dokumentaˇcn´ıho projektu
Literatura - programov´an´ı
1. Stevens, W. R., Rago, S. A.: Advanced Programming in UNIX(r) Environment. Addison-Wesley, 2nd edition, 2005. 2. Rochkind, M. J.: Advanced UNIX Programming, Addison-Wesley; 2nd edition, 2004 3. Stevens, W. R., Fenner B., Rudoff, A. M.: UNIX Network Programming, Vol. 1 – The Sockets Networking API. Prentice Hall, 3rd edition, 2004 4. Butenhof, D. R.: Programming with POSIX Threads, Addison-Wesley; 1st edition, 1997 5. Unixov´especifikace, viz http://www.unix.org 6. manu´alov´estr´anky (zejm. sekce 2, 3)
1. pravdˇepodobnˇenen´ı lepˇs´ıknihy o programov´an´ıpod Unixem (neobsahuje s´ıt’ov´eprogramov´an´ı, to je v knize 3) 2. aktualizovan´evyd´an´ıdalˇs´ız klasick´ych knih o programov´an´ıpod Unixem. Obsahuje i s´ıt’ov´eprogramov´an´ıa aˇcsamozˇrejmˇenen´ı tak podrobn´a jako spojen´ıknih 1 a 3, m˚uˇze to b´yt nˇekdy naopak v´yhodou. Tuto knihu jedno- znaˇcnˇedoporuˇcuji, pokud chcete nˇeco kupovat. 3. klasick´akniha o s´ıt’ov´em programov´an´ı, jedna z nejlepˇs´ıch k tomuto t´ematu; existuje i druh´yd´ıl UNIX Network Programming, Volume 2: In- terprocess Communications, kter´ase zab´yv´akomunikac´ımezi procesy (roury, POSIX IPC, System V IPC, synchronizace vl´aken, RPC). 4. velmi dobr´aa podrobn´akniha o programov´an´ıs vl´akny 5. domovsk´astr´anka posledn´ıch specifikac´ırozhran´ıUNIXu 6. podrobn´ypopis jednotliv´ych funkc´ı (v Linuxu bˇeˇznˇe ne zcela dostaˇcuj´ıc´ı; manu´alov´estr´anky v tomto syst´emu jsou ˇcasto horˇs´ıkvality neˇzu syst´em˚u ostatn´ıch)
5 . . . a spousta dalˇs´ıch knih, online dokumentac´ıa internetov´ych zdroj˚u, posledn´ı dobou vych´az´ıpomˇernˇehodnˇeknih o Linuxu, zamˇeˇren´ych na pouˇz´ıv´an´ıi programov´an´ı . . . jdˇete na http://www.amazon.com/ a zadejte kl´ıˇcov´eslovo “unix”. Pokud byste z Amazonu nˇeco kupovali, dejte pozor na to, ˇze mnoho knih m´aaktu- alizovan´avyd´an´ıi po nˇekolika m´alo letech, nˇekdy i levnˇejˇs´ıneˇzta p˚uvodn´ı, kter´ajsou vˇsak st´ale na skladu a v on-line nab´ıdce; tak at’ zbyteˇcnˇenekoup´ıte starˇs´ıvyd´an´ıneˇzto aktu´aln´ı. Nav´ıc se vyplat´ızkontrolovat i u pˇr´ısluˇsn´eho vydavatelstv´ı, ˇze nen´ıv brzk´edobˇenapl´anov´ano vyd´an´ınov´e– tato informace nˇekdy na Amazonu je, nˇekdy ne. . . . na Amazonu se m˚uˇze vyplatit nakoupit knihy z druh´eruky, protoˇze jsou ˇcasto v´yraznˇelevnˇejˇs´ıneˇzknihy nov´e. Probl´em je, ˇze vˇetˇsinou nen´ımoˇzn´eje poslat pˇr´ımo do CR,ˇ ale mus´ıv´am je nˇekdo pˇriv´ezt.
Literatura - historie UNIXu
• Peter Salus: A Quarter Century of UNIX, Addison-Wesley; 1st edition (1994) • Libes D., Ressler, S.: Life With Unix: A Guide for Everyone, Prentice Hall (1989) • Open Sources: Voices from the Open Source Revolution, kapitola Twenty Years of Berkeley Unix From AT&T-Owned to Freely Redistributable; O’Reilly (1999); on-line na webu . . . mnoho materi´al˚una webu; ˇcasto vˇsak obsahuj´ıc´ıne zcela pˇresn´e informace
• kapitola o BSD Unixu napsan´aMarshallem Kirk McKusickem je opravdu v´yborn´a
6 (Pre)historie UNIXu
• 1925 – Bell Telephone Laboratories – v´yzkum v komunikac´ıch (napˇr. 1947: transistor) v r´amci AT&T • 1965 – BTL s General Electric a MIT v´yvoj OS Multics (MULTIplexed Information and Computing System) • 1969 – Bell Labs opouˇst´ıprojekt, Ken Thompson p´ıˇse assembler, z´akladn´ıOS a syst´em soubor˚upro PDP-7 • 1970 – Multi-cs ⇒ Uni-cs ⇒ Uni-x • 1971 – UNIX V1, a portov´an na PDP-11 • prosinec 1971 – prvn´ıedice UNIX Programmer’s Manual
• AT&T = American Telephone and Telegraph Company • po odchodu BTL z projektu Multics prodala GE svoji poˇc´ıtaˇcovou divizi firmˇeHoneywell vˇcetnˇeprojektu Multics, kter´yse pak pod jej´ıpatronac´ıd´ale vyv´ıjel (virtu´aln´ı pamˇet’, multiprocesory, . . . ). Posledn´ı instalace Multics- u fungovala na kanadsk´em Ministerstvu obrany (Canadian Department of National Defence) a syst´em byl napˇr´ıklad jeˇstˇeaktivnˇepouˇz´ıv´an pro vojensk´e operace bˇehem v´alky v Persk´em z´alivu. Definitivn´ı shutdown byl proveden 31. ˇr´ıjna 2000. V´ıce informac´ına http://www.multicians.org. • pˇred poˇc´atkem pr´ace na v´yvojov´em prostˇred´ıpro PDP-7 napsal Thompson program Space Travel, kter´ybyl vyvinut na jin´em prostˇred´ı(Honeywell 635) a na p´asce pˇrenesen na PDP-7. • celkem bylo 10 edic´ıtohoto manu´alu, koresponduj´ıc´ıdeseti verz´ım UNIXu vznikl´ych v BTL. • UNIX V1 nemˇel pipe() !!! • za povˇsimnut´ıstoj´ı, ˇze UNIX je zhruba o 10 let starˇs´ıneˇzDOS • syst´em Multics mˇel 9 hlavn´ıch c´ıl˚u, jak pops´ano v ˇcl´anku Introduction and Overview of the Multics System z roku 1965. Za nejzaj´ımavˇejˇs´ı c´ıl bych povaˇzoval poˇzadavek na nepˇreruˇsovan´ybˇeh syst´emu. • Multics byl napsan´yv jazyce PL/I (Programming Language #1), tedy dˇr´ıve neˇzbyl UNIX pˇrepsan´ydo C ! • Multicsu byl v roce 1980 udˇelen jako prvn´ımu syst´emu level B2. Po nˇekolik let to byl jedin´ysyst´em s t´ımto bezpeˇcnost´ım levelem.
7 • GE byla zaloˇzena v roce 1892 slouˇcen´ım dvou spoleˇcnost´ı, z nichˇzjedna byla Edison General Electric Company zaloˇzen´aroku 1879 Thomasem Al- vou Edisonem (vyn´alezce ˇz´arovky, filmov´ekamery, . . . ); v souˇcasn´edobˇejej´ı dceˇrinn´espoleˇcnosti pokr´yvaj´ımnoho oblast´ı, vˇcetnˇedod´avky jednoho ze dvou typ˚umotor˚upro Airbus 380 nebo bankovnictv´ı. • PDP = Programmed Data Processor. Prvn´ıtyp, PDP-1, se prod´avala za $120.000 v dobˇe, kdy se jin´epoˇc´ıtaˇce prod´avaly za ceny pˇres mili´on. To byla tak´estrategie fy DEC - pojem computer tehdy znamenal drahou vˇec, potˇrebuj´ıc´ıs´al a t´ym lid´ı, kter´yse o to vˇsechno bude starat. Proto DEC sv´e maˇsiny nenaz´yval poˇc´ıtaˇci, ale pravˇeslovem PDPs. • PDP-11 je legend´arn´ımaˇsina od firmy DEC, postupnˇevznikaly verze PDP- 1 az PDP-16, kromˇePDP-2, PDP-13. Existuj´ıPDP-11 syst´emy, kter´ejeˇstˇe dnes bˇeˇz´ı, a tak´efirmy, kter´epro nˇevyr´abˇej´ın´ahradn´ıd´ıly.
Historie UNIXu, pokraˇcov´an´ı • ´unor 1973 – UNIX V3 obsahoval cc pˇrekladaˇc(jazyk C byl vytvoˇren Dennisem Ritchiem pro potˇreby UNIXu) • ˇr´ıjen 1973 – UNIX byl pˇredstaven veˇrejnosti ˇcl´ankem The UNIX Timesharing System na konferenci ACM • listopad 1973 – UNIX V4 pˇreps´an do jazyka C • 1975 – UNIX V6 byl prvn´ıverz´ıUNIXu bˇeˇznˇek dost´an´ımimo BTL • 1979 – UNIX V7, pro mnoh´e“the last true UNIX”, obsahoval uucp, Bourne shell; velikost kernelu byla pouze 40KB !!! • 1979 – UNIX V7 portov´an na 32-bitov´yVAX-11 • 1980 – Microsoft pˇr´ıch´az´ıs XENIXem, kter´yje zaloˇzen´yna UNIXu V7
• ACM = Association for Computing Machinery, zaloˇzena 1947. • akt pˇreps´an´ıUNIXu do jazyka C byl moˇzn´anejv´yznamnˇejˇs´ım mo- mentem v historii tohoto syst´emu ⇒ UNIX mohl b´yt mnohem jed- noduˇseji portov´an na jin´earchitektury • na verzi 6 je zaloˇzena legend´arn´ıkniha A commentary on the Unix Operating System, jej´ıˇzautorem je John Lions. • Microsoft neprod´aval XENIX pˇr´ımo, ale licencoval ho OEM v´yrobc˚um (Ori- ginal Equipment Manufacturer) jako byl Intel, SCO a jin´ı. Jin´efirmy pak XENIX d´ale portovaly na 286 (Intel) a 386 (SCO, 1987). Na webu je moˇzn´e naj´ıt zaj´ımav´einformace popisuj´ıc´ıtuto dobu a tehdy kladn´yvztah Micro- softu k UNIXu.
8 • pokud v´as v´ıce zaj´ım´ahistorie unixu, pod´ıvejte se na wikipedii na heslo “unix” a skrz odkazy m´ate na dlouho co ˇc´ıst.
Divergence UNIXu
• pol. 70. let – uvolˇnov´an´ıUNIXu na univerzity: pˇredevˇs´ım University of California v Berkeley • 1979 – z UNIX/32V (zm´ınˇen´yport na VAX) poskytnut´eho do Berkeley se vyv´ıj´ı BSD Unix (Berkeley Software Distribution) verze 3.0; posledn´ıverze 4.4 v roce 1993 • 1982 AT&T, vlastn´ık BTL, m˚uˇze vstoupit na trh poˇc´ıtaˇc˚u (zak´az´ano od roku 1956) a pˇr´ıch´az´ıs verz´ı System III (1982) aˇz V.4 (1988) – tzv. SVR4 • vznikaj´ıUNIX International, OSF (Open Software Foundation), X/OPEN, ... • 1991 – Linus Torvalds zah´ajil v´yvoj OS Linux, verze j´adra 1.0 byla dokonˇcena v r. 1994
• UNIX je univerz´aln´ıoperaˇcn´ısyst´em funguj´ıc´ına ˇsirok´eˇsk´ale poˇc´ıtaˇc˚uod embedded a handheld syst´em˚u(Linux), pˇres osobn´ı poˇc´ıtaˇce aˇzpo velk´e servery a superpoˇc´ıtaˇce. • UNIX V3 = UNIX verze 3, UNIX V.4 = system 5 release 4 atd., tj. UNIX V3 != SVR3. • UNIX System III tedy nen´ıUNIX V3; v t´eto dobˇe(pozdn´ı70. l´eta) bylo v BTL nˇekolik skupin, kter´epˇr´ısp´ıvaly do v´yvoje UNIXu. Vx verze byly vyv´ıjeny v r´amci Computer Research Group, dalˇs´ıskupiny byly Unix System Group (USG), Programmer’s WorkBench (PWB). Dalˇs´ı vˇetv´ı UNIXu byl Columbus UNIX t´eˇzv r´amci BT. Na tˇechto r˚uzn´ych verz´ıch je pr´avˇezaloˇzena verze System III. Z´ajemce o v´ıce informac´ıodkazuji na web. • UNIX se rozˇstˇepil na dvˇehlavn´ı vˇetve: AT&T a BSD, jednotliv´ı v´yrobci pˇrich´azeli s vlastn´ımi modifikacemi. Jednotliv´eklony od sebe navz´ajem pˇreb´ıraly vlastnosti. • Berkeley univerzita z´ıskala jako jedna z prvn´ıch licenci UNIXu v roce 1974. Bˇehem nˇekolika let studenti (jedn´ım z nich byl Bill Joy, pozdˇejˇs´ızakladatel firmy Sun Microsystems a autor C-shellu) vytvoˇrili SW bal´ık Berkeley Soft- ware Distribution (BSD) a prod´avali ho v roce 1978 za $50. Tyto poˇc´ateˇcn´ı verze BSD obsahovaly pouze SW a utility (prvn´ı verze: Pascal pˇrekladaˇc, editor ex), ne syst´em ani ˇz´adn´ejeho zmˇeny. To pˇriˇslo aˇzs verz´ı3BSD. verze 4BSD vznik´aroku 1980 jiˇzjako projekt financovan´yagenturou DARPA a veden´yBillem Joyem. Trp´ıprobl´emy spojen´ymi s nedostateˇcn´ym v´ykonem a vznik´atak vyladˇen´ysyst´em 4.1BSD dod´avan´yod roku 1981.
9 • 4.1BSD mˇelo b´yt p˚uvodnˇe5BSD, ale pot´e, co AT&T vzneslo n´amitky, ˇze by si z´akazn´ıci mohli pl´est 5BSD se syst´emem System V, pˇreˇslo BSD na ˇc´ıslov´an´ı 4.xBSD. Bˇeˇznou vˇec´ıbylo, ˇze neˇzps´at vlastn´ık´od, v´yvoj´aˇri z Berkeley se radˇeji nejdˇr´ıve pod´ıvali kolem, co je jiˇzhotov´e. Tak BSD napˇr´ıklad pˇrevzalo virtu´aln´ıpamˇet’ z Machu a nebo NFS-compatibiln´ık´od vyvinut´yna jedn´e kanadsk´euniverzitˇe. • v´yrobci hardware dod´avali varianty UNIXu pro sv´epoˇc´ıtaˇce a komercializace tak jeˇstˇezhorˇsila situaci co t´yˇce diverzifikace UNIXu • v 80-t´ych letech se proto zaˇcaly objevovat snahy o standardizaci. Standard ˇr´ık´a, jak m´avypadat syst´em navenek (pro uˇzivatele, program´atora a spr´avce), nezab´yv´ase implementac´ı. C´ılem je pˇrenositelnost aplikac´ıi uˇzivatel˚u. vˇsechny syst´emy totiˇzz d´alky vypadaly jako UNIX, ale z bl´ızka se liˇsily v mnoha d˚uleˇzit´ych vlastnostech. System V a BSD se napˇr. liˇsily v pouˇzit´em file- syst´emu, s´ıt’ov´earchitektuˇre i v architektuˇre virtu´aln´ıpamˇeti. • kdyˇzv roce 1987 firmy AT&T a Sun (jehoˇztehdejˇs´ıSunOS byl zaloˇzen´yna BSD) spojily svoje ´usil´ına vyvinut´ıjednoho syst´emu, kter´yby obsahoval to nejlepˇs´ız obou vˇetv´ı, kromˇenadˇsen´ych reakc´ıto vzbudilo i strach u mnoha dalˇs´ıch v´yrobc˚uunixov´ych syst´em˚u, kteˇr´ı se b´ali, ˇze by to pro obˇefirmy znamenalo obrovskou komerˇcn´ıv´yhodu. Vznik´aproto Open Software Foun- dation (nezamˇeˇnovat za FSF), a zakl´adaj´ıc´ımi ˇcleny byly mimo jin´efirmy Hewlett-Packard, IBM a Digital. Z toho vzeˇsl´ysyst´em OSF/1 ale nebyl pˇr´ıliˇs ´uspˇeˇsn´y, a dod´aval ho pouze Digital, kter´yho pˇrejmenoval na Digital UNIX. Zaj´ımavost´ıje, ˇze syst´em je postaven´yna mikroj´adru Mach. Po akvizici Digi- talu Compaqem byl syst´em pˇrejmenov´an na Tru64 a s t´ımto jm´enem je d´ale podporov´an firmou Hewlett-Packard, kter´ase v roce 2002 s Compaqem spo- jila. Mezit´ım firmy AT&T a Sun kontrovaly zaloˇzen´ım UNIX International. Toto obdob´ıpˇrelomu 80-t´ych a 90-t´ych let se naz´yv´a Unix Wars – boj o to, co bude “standardn´ım unixem”. • OSF a UI se staly velk´ymi rivaly, ale velmi rychle se stˇretly s neˇcekan´ym protivn´ıkem - s firmou Microsoft. • (1992) 386BSD zaloˇzen´ena Networking Release 2 ; Bill Jolitz vytvoˇril 6 chybˇej´ıc´ıch soubor˚ua dal tak dohromady funkˇcn´ıBSD syst´em pro i386. Tento syst´em se stal z´akladem syst´em˚u NetBSD a FreeBSD (a dalˇs´ıch, z tˇechto dvou syst´em˚uvych´azej´ıc´ıch). • (1995) 4.4BSD-Lite Release 2, po kter´en´asleduje rozpuˇstˇen´ıCSRG, kter´a skoro 20 let pilotovala v´yvoj BSD vˇetve. V´ıce jiˇzzm´ınˇen´akapitola o BSD Unixu.
10 Souˇcasn´eUNIXy Hlavn´ıkomerˇcn´ıunixov´esyst´emy: • Sun Microsystems: SunOS (nen´ıjiˇzd´ale vyv´ıjen), Solaris • SGI: IRIX • IBM: AIX • HP: HP-UX • HP (pˇredt´ım Compaq): Tru64 UNIX • SCO: SCO Unix • Novell: UNIXware Open source: • FreeBSD, NetBSD, OpenBSD, OpenSolaris • Linux distribuce
• kdyˇzjsem cca v roce 1998 projel nmapem vˇsechny DNS root servery, abych zjistil na kter´ych syst´emech bˇeˇz´ı, bylo 80% z nich na SunOS/Solaris. IRIX je zase syst´em, kter´ypo mnoho let ovl´adal televizn´ı/filmov´ypr˚umysl (napˇr. Pixar studio kde na IRIXu vznikly filmy jako A Bug’s Life, Toy Story a dalˇs´ı). A na AIX napˇr´ıklad bˇeˇzel Blue Deep, paraleln´ısuperpoˇc´ıtaˇc, kter´yv roce 1997 porazil v ˇsesti fascinuj´ıc´ıch z´apasech 3.5 ku 2.5 ´uˇraduj´ıc´ıho velmistra ˇsachu Garriho Kasparova. Jin´ymi slovy – kaˇzd´ysyst´em m´asvoje ´uspˇechy. • jak jiˇzbylo zm´ınˇeno, Tru64 UNIX vych´az´ız OSF/1 firmy DEC. Ta pˇredt´ım dod´avala Ultrix, zaloˇzen´yna BSD unixu. • OpenSolaris je projekt vznikl´yv ˇcervnu 2005 a je zaloˇzen na podmnoˇzinˇe zdrojov´ych text˚uv´yvojov´everze Solarisu (kernel, knihovny, pˇr´ıkazy) k datu uveden´ı. Ofici´aln´ıdistribuce zaloˇzen´ana OpenSolarisu se jmenuje Solarix Ex- press. Distribuce vzeˇsl´ez komunity jsou napˇr´ıklad LiveCD BeleniX, SchilliX a Nexenta. • pozor na to, ˇze Linux je pouze j´adro, ne syst´em, na rozd´ıl tˇreba od FreeBSD. OpenSolaris je nˇeco mezi t´ım, j´adro + drivery, z´akladn´ı pˇr´ıkazy a knihovny, a v bin´arn´ıpodobˇeto m´anˇeco pˇres 100MB. V obou pˇr´ıpadech je tedy spr´avn´e pouˇz´ıvat spojen´ı“Linux (OpenSolaris) distribuce”, kdyˇzse bav´ıme o cel´em syst´emu. • kaˇzd´akomerˇcn´ıvarianta vych´azela z jednoho ze dvou hlavn´ıch syst´em˚u– UNIX V nebo BSD, a pˇrid´avala si sv´evlastnosti • vznik´avelk´ypoˇcet r˚uzn´ych standard˚u(viz n´asleduj´ıc´ı strana), skoro jako poˇcet r˚uzn´ych verz´ıUNIX˚u. Nakonec se vˇetˇsina v´yrobc˚ushodla na nˇekolika z´akladn´ıch standardech.
11 • graf zn´azorˇnuj´ıc´ıhistorii Unixu a z´avislosti mezi syst´emy na 19-ti A4 listech ve form´atu PS/PDF je k nalezen´ına http://www.levenez.com/unix
12 Standardy UNIXu
• SVID (System V Interface Definition) – ,,fialov´akniha”, kterou AT&T vydala poprv´ev roce 1985 – dnes ve verzi SVID3 (odpov´ıd´aSVR4) • POSIX (Portable Operating System based on UNIX) – s´erie standard˚uorganizace IEEE znaˇcen´aP1003.xx, postupnˇeje pˇrej´ım´avrcholov´ynadn´arodn´ıorg´an ISO • XPG (X/Open Portability Guide) – doporuˇcen´ıkonsorcia X/Open, kter´ebylo zaloˇzeno v r. 1984 pˇredn´ımi v´yrobci platforem typu UNIX • Single UNIX Specification – standard organizace The Open Group, vznikl´ev roce 1996 slouˇcen´ım X/Open a OSF – dnes Version 3 (UNIX 03), pˇredchoz´ıVersion 2 (UNIX 98) – splnˇen´ıje nutnou podm´ınkou pro uˇzit´ıobchodn´ıho n´azvu UNIX
• AT&T dovolila v´yrobc˚um naz´yvat svoji komerˇcn´ıUNIX variantu “System V” pouze pokud splˇnovala podm´ınky standardu SVID. AT&T tak´e publikovala System V Verification Suite (SVVS), kter´eovˇeˇrilo, zda dan´ysyst´em odpov´ıd´a standardu. • POSIX (Portable Operating System Interface) je standardizaˇcn´ısnaha or- ganizace IEEE (Institute of Electrical and Electronics Engineers). Prvn´ım dokumentem je IEEE Std POSIX1003.1-1988, dˇr´ıve oznaˇcovan´yprostˇejako POSIX, dnes zn´am´ysp´ıˇse jako POSIX.1, protoˇze POSIXem se nyn´ım´ın´ısada vz´ajemnˇesouvisej´ıc´ıch standard˚u. POSIX.1 obsahuje programovac´ıAPI, tj. pr´ace s procesy, sign´aly, soubory, ˇcasovaˇci atd. S mal´ymi zmˇenami byl pˇrevzat organizac´ıISO, a oznaˇcovan´yjako POSIX1990. Tento standard byl s´am o sobˇevelk´y´uspˇech, ale st´ale jeˇstˇenespojoval t´abory System V a BSD, protoˇze v sobˇenapˇr´ıklad nezahrnoval BSD sockety nebo IPC (semafory, zpr´avy, sd´ılen´apamˇet’) ze System V. Oznaˇcen´ıPOSIX vymyslel Richard Stallman, tedy ˇclovˇek, kter´yv roce 1983 zaloˇzil GNU projekt. Souˇc´ast´ıstandardu je i “POSIX conformance test suite (PCTS)”, kter´yje volnˇek dispozici. • SUSV3 je spoleˇcn´ystandard The Open Group, IEEE (Std. 1003.1, 2003 Edi- tion) a ISO (ISO/IEC 9945-2003). • dnes je asi nejd˚uleˇzitˇejˇs´ıSingle UNIX Specification, kter´ese budeme drˇzet i my. Tato norma je podm´ınkou pro uˇzit´ın´azvu UNIX, Je postavena na b´azi POSIXu. Popis datov´ych struktur a algoritm˚uj´adra v tomto materi´alu bude vˇetˇsinou vych´azet ze System V Rel. 4.
13 Jazyk C
• t´emˇeˇrcel´yUNIX je napsan´yv C, pouze nejniˇzˇs´ıstrojovˇez´avisl´a ˇc´ast v assembleru ⇒ pomˇernˇesnadn´apˇrenositelnost • navrhl Dennis Ritchie z Bell Laboratories v roce 1972. • n´asledn´ık jazyka B od Kena Thomsona z Bell Laboratories. • vytvoˇren jako prostˇredek pro pˇrenos OS UNIX na jin´epoˇc´ıtaˇce – siln´avazba na UNIX. • varianty jazyka: – p˚uvodn´ıK&R C – standard ANSI/ISO C • ´uspˇech jazyka C daleko pˇres´ahl ´uspˇech samotn´eho UNIXu
• CPL ⇒ BCPL ⇒ B (Thompson, interpret) ⇒ C • K&R C – jazyk C tak, jak je popsan´yv klasick´eknize Brian W. Kernighan, Dennis M. Ritchie: The C Programming Language (Prentice-Hall, 1978). • v roce 1983 ANSI (American National Standards Institute) zformoval v´ybor pro vytvoˇren´ıC standardu. Po dlouh´em a pracn´em procesu byl v roce 1989 standard koneˇcnˇehotov, a je zn´am´ynejˇcastˇeji jako “ANSI C”, pˇr´ıpadnˇejako C89 (napˇr´ıklad pˇrekladaˇcpro tuto normu se v Sun Studiu jmenuje c89, jelikoˇz i to samotn´ejm´eno programu mus´ıb´yt podle normy). Druh´e vyd´an´ıK&R knihy (1988) je jiˇzupraven´epr´avˇepro nadch´azej´ıc´ı ANSI C. V roce 1990 bylo ANSI C adoptov´ano organizac´ıISO jako ISO/IEC 9899:1990; tento C standard tak m˚uˇze b´yt nˇekdy oznaˇcov´an i jako C90. • se C standardem se pak nˇejakou dobu neh´ybalo, aˇzna konci 90-t´ych let proˇsel dalˇs´ıreviz´ıv r´amci ISO a vznik´aISO 9899:1999, ˇcastˇeji oznaˇcovan´yjako C99. V roce 2000 pak naopak tento standard pˇrevzal ANSI. • rozd´ıly mezi C89 a C99 jsou mimo jin´ezahrnut´ıinline funkc´ı, definic´ıpro- mˇenn´ych napˇr´ıklad i do for konstrukce, jednoˇr´adkov´ych koment´aˇr˚upomoc´ı //, nov´ych funkc´ıjako snprintf() apod.
14 Form´aty dat
• poˇrad´ıbajt˚u– z´avis´ına architektuˇre poˇc´ıtaˇce – big endian: 0x11223344 = 11 22 33 44 addr + 0 1 2 3
– little endian: 0x11223344 = 44 33 22 11 addr + 0 1 2 3 • ˇr´adky textov´ych soubor˚ukonˇc´ıv UNIXu znakem LF (nikoliv CRLF). Vol´an´ı putc(’\n’) tedy p´ıˇse pouze jeden znak. • big endian – SPARC, MIPS, s´ıt’ov´epoˇrad´ıbajt˚u • little endian – Intel
• velk´ypozor na v´ystupy program˚utypu hexdump, kter´edefaultnˇevypisuj´ı soubor ve 2-bajtov´ych ˇc´ıslech, coˇzsv´ad´ıvidˇet soubor jinak, neˇzjak je opravdu zapsan´yna disku; viz pˇr´ıklad (i386, FreeBSD):
$ echo -n 1234 > test $ hexdump test 0000000 3231 3433 0000004
je samozˇrejmˇemoˇzn´epouˇz´ıt jin´yform´at v´ystupu:
$ hexdump -C test 00000000 31 32 33 34 |1234| 00000004
• UNIX norma pˇr´ıkaz hexdump nem´a, ale definuje od (octal dump), takˇze zde je jeho hexdumpu ekvivalentn´ıform´at v´ypisu na SPARCu (Solaris); vˇsimnˇete si zmˇeny oproti v´ypisu pod FreeBSD!
$ od -tx2 test 0000000 3132 3334 0000004
15 Deklarace a definice funkce • K&R – deklarace n´avratov´y_typ indentifik´ator(); – definice n´avratov´y_typ indentifik´ator(par [,par...]); typ par;... { /* tˇelo funkce */ } • ANSI – deklarace n´avratov´y_typ indentifik´ator(typ par [,typ par...]); – definice n´avratov´y_typ indentifik´ator(typ par [,typ par...]); { /* tˇelo funkce */ }
• pouˇz´ıvejte pouze novˇejˇs´ı(ANSI) typ deklarac´ıa vˇzdy deklarujte prototypy funkc´ı, tj. inkludujte hlaviˇckov´esoubory. V´yjimkou m˚uˇze asi jen to, pokud budete pracovat s k´odem, kter´ybyl napsan´ypodle K&R.
• r˚uzn´ymi z´apisy deklarac´ıse dost´av´ame rovnou i k r˚uzn´ym styl˚um psan´ızdro- jov´ych text˚u. Nˇekter´esyst´emy to pˇr´ıliˇsneˇreˇs´ı (Linux), jin´esyst´emy maj´ı velmi striktn´ıpravidla pro psan´ızdrojov´ych text˚u(napˇr. Solaris, viz on-line C Style and Coding Standards for SunOS). Skoro kaˇzd´yUNIXov´ysyst´em m´aprogram indent(1), kter´yv´am pomoc´ıpˇrep´ınaˇc˚upˇreform´atuje jak´ykoli C zdrojov´ytext do poˇzadovan´eho v´ystupu.
16 C style
• vˇec zd´anlivˇepodˇradn´a, pˇritom extr´emnˇed˚uleˇzit´a– ´uprava zdrojov´ych k´od˚uprogramu • mnoho zp˚usob˚ujak ano: int main(void) { char c; int i = 0;
printf("%d\n", i); return (0); }
• u C stylu je nejd˚uleˇzitˇejˇs´ı to, aby byl konzistentn´ı. Pokud skupina pro- gram´ator˚upracuje na jednom projektu, nen´ızas aˇztak d˚uleˇzit´e, na jak´em stylu se dohodnout (pokud je alespoˇntrochu rozumn´y), ale aby se dohodli. Jednotn´ya dobˇre zvolen´ystyl ˇsetˇr´ıˇcas a br´an´ızbyteˇcn´ym chyb´am.
17 C style (cont.) • mnoho zp˚usob˚ujak NE (tzv. assembler styl): int main(void) { int i = 0; char c; printf("%d\n", i); return (0); } • nebo (schizofrenn´ıstyl): int main(void) { int i = 0; char c; if (1) printf("%d\n", i);i=2; return (0); }
• pamatujte na to, ˇze dobr´ystyl zdrojov´ych k´od˚uje i vizitkou program´atora. Kdyˇzse v r´amci pˇrij´ımac´ıch pohovor˚uodevzd´avaj´ıi uk´azkov´ek´ody, tak hlavn´ı d˚uvod nen´ıten, aby se zjistilo, ˇze v´am dan´yprogram funguje. . . Uprava´ sa- motn´eho zdrojov´eho textu je jedn´ım z kriteri´ı, protoˇze to pˇrenesenˇem˚uˇze svˇedˇcit i o dalˇs´ıch skuteˇcnostech – nˇekdo napˇr. bude odhadovat, ˇze po- kud p´ıˇsete neˇcist´ya neupraven´yk´od, tak jste moˇzn´a jeˇstˇenepracovali na nˇeˇcem opravdu sloˇzit´em ˇci nˇeˇcem zahrnuj´ıc´ım spolupr´aci s v´ıce program´atory, protoˇze v tom pˇr´ıpadˇeje rozumnˇeˇcist´yk´od jednou z podm´ınek ´uspˇechu a jednou ze zkuˇsenost´ı, kter´ez takov´espolupr´ace vych´azej´ı. Toto je samozˇrejmˇe zˇc´asti subjektivn´ın´azor, ale ˇcist´ym k´odem nic nezkaz´ıte, minim´alnˇenekaz´ıte oˇci sv´ym cviˇc´ıc´ım.
18 Utility
cc, c99∗, gcc† pˇrekladaˇcC CC, g++† pˇrekladaˇcC++ ld spojovac´ıprogram (linker) ldd pro zjistˇen´ız´avislost´ıdynamick´eho objektu cxref ∗ kˇr´ıˇzov´eodkazy ve zdrojov´ych textech v C sccs∗, rcs,cvs spr´ava verz´ızdrojov´eho k´odu make∗ ˇr´ızen´ıpˇrekladu podle z´avislost´ı ar∗ spr´ava knihoven objektov´ych modul˚u dbx, gdb† debuggery prof, gprof † profilery ∗ UNIX 03 † GNU
UNIX 03 • standardn´ıpˇr´ıkaz vol´an´ıkompil´atoru a linkeru C je c99 (podle ISO normy pro C z roku 1999) • cb (C program beautifier) nen´ı • pro spr´avu verz´ıje sccs • debuggery a profilery nejsou
19 Konvence pro jm´ena soubor˚u
*.c jm´ena zdrojov´ych soubor˚uprogram˚uv C *.cc jm´ena zdrojov´ych soubor˚uprogram˚uv C++ *.h jm´ena hlaviˇckov´ych soubor˚u(header˚u) *.o pˇreloˇzen´emoduly (object files) a.out jm´eno spustiteln´eho souboru (v´ysledek ´uspˇeˇsn´ekompilace)
/usr/ koˇren stromu syst´emov´ych header˚u /usr/lib/lib*.a statick´eknihovny objektov´ych modul˚u /usr/lib/lib*.so um´ıstˇen´ıdynamick´ych sd´ılen´ych knihoven objektov´ych modul˚u
statick´eknihovny – pˇri linkov´an´ıse stanou souˇc´ast´ıv´ysledn´eho spustiteln´eho programu. Dnes se uˇzmoc nepouˇz´ıv´a. sd´ılen´eknihovny – program obsahuje pouze odkaz na knihovnu, pˇri spuˇstˇen´ı pro- gramu se potˇrebn´eknihovny naˇctou do pamˇeti ze soubor˚u *.so a pˇrilinkuj´ı.
• dnes se vˇetˇsinou pouˇz´ıvaj´ısd´ılen´eknihovny, protoˇze nezab´ıraj´ıtolik diskov´eho prostoru (knihovna je na disku jednou, nen´ısouˇc´ast´ıkaˇzd´eho spustiteln´eho souboru) a snadnˇeji se upgraduj´ı(staˇc´ıinstalovat novou verzi knihovny, nen´ı tˇreba pˇrelinkovat programy). Posledn´ı verze Solarisu uˇz napˇr´ıklad v˚ubec neobsahuje libc.a, d´ıky ˇcemuˇzjiˇzprogram´ator nem˚uˇze vytvoˇrit statickou bin´arku, aniˇzby nemˇel dostateˇcn´eznalosti syst´emu. • nˇekdy se bez statick´ych knihoven neobejdeme. V nˇekter´ych situac´ıch nen´ı moˇzn´epouˇz´ıt knihovny dynamick´e, spustiteln´esoubory jsou takzvan´e standa- lone binaries a pouˇzit´ınaleznou napˇr´ıklad pˇri bootov´an´ıoperaˇcn´ıho syst´emu.
20 Princip pˇrekladu
zdrojov´emoduly objektov´emoduly program main.c main.o a.out main() { main msg(); msg ?? main } msg util.c util.o msg() { pˇrekladaˇc msg msg puts(); } puts ?? linker puts
syst´emov´a puts puts knihovna
• u sloˇzitˇejˇs´ıch program˚ub´yv´azvykem rozdˇelit zdrojov´ytext programu do nˇekolika modul˚u, kter´eobsahuj´ıpˇr´ıbuzn´efunkce a tyto moduly se pak mohou pˇrekl´adat zvl´aˇst’ (dokonce kaˇzd´ymodul m˚uˇze b´yt v jin´em jazyce a pˇrekl´ad´an jin´ym pˇrekladaˇcem). V´yhodou je jednak urychlen´ıpˇrekladu (pˇrekl´adaj´ıse vˇzdy jen moduly zmˇenˇen´eod posledn´ıho pˇrekladu) a jednak flexibilita (nˇek- ter´emoduly se mohou pouˇz´ıvat v r˚uzn´ych programech). Pro ˇr´ızen´ıpˇrekladu se obvykle pouˇz´ıv´autilita make. • pˇrekladaˇc jednotliv´ezdrojov´emoduly pˇreloˇz´ıdo tvaru tzv. objektov´ych mo- dul˚u, jeˇzobsahuj´ık´od programu (vˇcetnˇevol´an´ılok´aln´ıch funkc´ı), ale nam´ısto vol´an´ıextern´ıch funkc´ıobsahuj´ıjen tabulku jejich jmen. • po f´azi pˇrekladu nastupuje spojovac´ıprogram (t´eˇz linker editor nebo loader), kter´yzkompletuje v´ysledn´yprogram vˇcetnˇevyˇreˇsen´ıextern´ıch odkaz˚umezi moduly a syst´emov´ymi knihovnami resp. mezi moduly navz´ajem. • pouˇzit´estatick´eknihovny jsou zkop´ırov´any do spustiteln´eho souboru. Na sd´ılen´eknihovny jsou ve spustiteln´em souboru pouze odkazy a linkuje je runtime linker pˇri kaˇzd´em spuˇstˇen´ıprogramu. V´ıce viz dynamick´ylinker na stranˇe31.
• pomoc´ı parametr˚ulinkeru lze urˇcit, zda se budou pouˇz´ıvat statick´enebo dynamick´eknihovny. Zdrojov´yk´od je v obou pˇr´ıpadech stejn´y. Existuje i mechanismus (dlopen(), dlsym(). . . ), pomoc´ıkter´eho se za bˇehu programu vybere sd´ılen´aknihovna a daj´ıse volat jej´ıfunkce. T´ımto zp˚usobem m˚uˇzete tak´ezjistit, zda v syst´emu je pˇr´ıtomna pˇr´ısluˇsn´afunkcionalita a pokud ne, zachovat se podle toho.
21 Pˇreklad jednoho modulu (preprocesor)
main.c #include
int puts(char *s); preprocesor { mydef.h puts("Ahoj"); #define MSG "Ahoj" } extern int var a;
• preprocesor prov´ad´ıexpanzi maker, ˇcten´ıvloˇzen´ych () soubor˚ua vynech´av´a koment´aˇre. • v´ystup preprocesoru lze z´ıskat pomoc´ı cc -E pˇr´ıpadnˇepˇr´ımo zavol´an´ım cpp, nemus´ıto b´yt ale vˇzdz tot´eˇzprotoˇze nˇekter´epˇrekladaˇce maj´ıpreprocesor integrov´an v sobˇe. Preprocesor m˚uˇzete samozˇrejmˇepouˇz´ıvat i pro jin´epro- jekty, kter´es pˇrekladem zdrojov´ych soubor˚uv jazyce C nemus´ım´ıt v˚ubec nic spoleˇcn´eho. • pouˇzit´ıpreprocesoru se m˚uˇze velmi hodit v situaci, kdy potˇrebujete zas´ahnout do ciz´ıho k´odu, pln´eho podm´ıneˇcn´ych vkl´ad´an´ır˚uzn´ych hlaviˇckov´ych sou- bor˚ua r˚uzn´ych definic z´avisl´ych na dan´ych podm´ınk´ach. Pˇri hled´an´ıp˚uvodce chyby v´am pr´avˇem˚uˇze hodnˇepomoci samostatn´eho zpracov´an´ıvstupn´ıho souboru pomoc´ıpreprocesuru, kde probl´em jiˇzvˇetˇsinou rozpozn´ate snadno. • cpp v´am dok´aˇze na standardn´ıchybov´yv´ystup zobrazit i cel´ystrom vkl´ada- n´ych soubor˚u, coˇzopˇet pˇri podm´ıneˇcn´ych pˇrekladech m˚uˇze b´yt velmi uˇziteˇcn´a vˇec. Staˇc´ıpro to pouˇz´ıt volbu -H a pˇresmˇerovat v´ystup do /dev/null ˇc´ımˇz dostanete pouze hierarchii vkl´adan´ych hlaviˇckov´ych soubor˚u.
22 Pˇreklad jednoho modulu (kompil´ator)
main.s main.i .globl main int puts(char *s); .type main, @function main: extern int var a; pushhl %ebp movl %esp, %ebp main() pushl $.LC0 call puts { kompil´ator addl $4, %esp puts("Ahoj"); .L1: } leave ret
• pˇreklad z C do assembleru • v´ystup t´eto f´aze pˇrekladu lze z´ıskat pomoc´ı cc -S.
23 Pˇreklad jednoho modulu (assembler)
main.s .globl main .type main, @function main.o main: 457f 464c 0101 0001 pushhl %ebp movl %esp, %ebp 0000 0000 0000 0000 pushl $.LC0 0001 0003 0001 0000 call puts 0000 0000 0000 0000 addl $4, %esp assembler 00ec 0000 0000 0000 .L1: 0034 0000 0000 0028 leave ret
• pˇreklad z assembleru do strojov´eho k´odu • objektov´ymodul je v´ysledkem pˇr´ıkazu cc -c.
24 Kompil´ator
• vol´an´ı: cc [options ] soubor ... • nejd˚uleˇzitˇejˇs´ıpˇrep´ınaˇce: -o soubor jm´eno v´ysledn´eho souboru -c pouze pˇreklad (nelinkovat) -E pouze preprocesor (nepˇrekl´adat) -l slinkuj s pˇr´ısluˇsnou knihovnou -Ljm´eno pˇridej adres´aˇrpro hled´an´ıknihoven z -l -Olevel nastaven´ı´urovnˇeoptimalizace -g pˇreklad s ladic´ımi informacemi -Djm´eno definuj makro pro preprocesor -Iadres´aˇr um´ıstˇen´ı #include soubor˚u
• -l/-L jsou pˇrep´ınaˇce linker editoru, tj. kompil´ator pˇr´ısluˇsn´einformace pˇred´a, ale jsou pouˇz´ıv´any tak ˇcasto, ˇze jsou vloˇzeny i do tohoto slajdu. • kompil´ator a linker maj´ımnoho dalˇs´ıch pˇrep´ınaˇc˚uovlivˇnuj´ıc´ıch generovan´y k´od, vypisov´an´ıvarovn´ych hl´aˇsen´ınebo variantu jazyka (K&R/ANSI). Je tˇreba nastudovat dokumentaci konkr´etn´ıho produktu.
25 Pˇreddefinovan´amakra __FILE__, __LINE__, __DATE__, __TIME__, __cplusplus, apod. jsou standardn´ımakra kompil´atoru C/C++ unix vˇzdy definov´ano v Unixu mips, i386, sparc hardwarov´aarchitektura linux, sgi, sun, bsd klon operaˇcn´ıho syst´emu _POSIX_SOURCE, _XOPEN_SOURCE pˇreklad podle pˇr´ısluˇsn´enormy
pro pˇreklad podle urˇcit´enormy by pˇred prvn´ım #include mˇel b´yt ˇr´adek s definic´ın´asleduj´ıc´ıho makra. Pak naˇctˇete unistd.h. UNIX 98 #define _XOPEN_SOURCE 500 SUSv3 #define _XOPEN_SOURCE 600 POSIX1990 #define _POSIX_SOURCE
• funguje to tak, ˇze pomoc´ı konkr´etn´ıch maker definujete co chcete (napˇr. POSIX SOURCE) a podle nastaven´ıjin´ych maker (napˇr. POSIX VERSION) pak zjist´ıte, co jste dostali. Mus´ıte ale vˇzdy po nastaven´ı maker nainkludovat unistd.h. Napˇr´ıklad se pokus´ıme pˇreloˇzit program, kter´yvyˇzaduje SUS3, na syst´emu podporuj´ıc´ım SUS3 (Solaris 10), ale pˇrekladaˇcem, kter´ypodpo- ruje pouze SUS2 (UNIX03 pˇrekladaˇcje c99).
$ cat standards.c #define _XOPEN_SOURCE 600 /* you must #include at least one header !!! */ #include
• zdroj maker pro standard tedy m˚uˇze b´yt /usr//sys/feature tests.h na Solarisu. Bud’ ho najdete pˇr´ımo na Solaris syst´emu nebo pˇres code browser na www.opensolaris.org. • v dokumentaci konkr´etn´ıho kompil´atoru je moˇzn´enaj´ıt, kter´adalˇs´ımakra se pouˇz´ıvaj´ı. Mnoˇzstv´ımaker je definov´ano tak´ev syst´emov´ych hlaviˇckov´ych souborech.
26 • POSIX.1 v sobˇezahrnuje ANSI C; tedy C89, ne C99 (o C standardech v´ıce na stranˇe13). • co se t´yˇce maker k jednotliv´ym standard˚um, velmi dobr´a je kapitola 1.5 v [Rochkind]. Tak´edoporuˇcuji C program c1/suvreq.c k t´eto kapitole, kter´y je moˇzn´enaj´ıt i na m´ych str´ank´ach v sekci uk´azkov´ych pˇr´ıklad˚u. • mal´ypˇr´ıklad na podm´ınˇen´ypˇreklad:
int main(void) { #ifdef unix printf("yeah\n"); #else printf("grr\n"); #endif return (0); }
Linker
• Vol´an´ı: ld [options ] soubor ... cc [options ] soubor ... • Nejd˚uleˇzitˇejˇs´ıpˇrep´ınaˇce: -o soubor jm´eno v´ysledn´eho souboru (default a.out) -llib linkuj s knihovnou liblib.so nebo liblib.a -Lpath cesta pro knihovny (-llib ) -shared vytvoˇrit sd´ılenou knihovnu -non shared vytvoˇrit statick´yprogram
• linker je program, kter´yvezme typicky v´ıce objekt˚uvygenerovan´ych pˇrekla- daˇcem a vytvoˇr´ız nich bin´arn´ıprogram, knihovnu nebo dalˇs´ıobjekt vhodn´y pro dalˇs´ıf´azi linkov´an´ı. • pozor na to, ˇze na r˚uzn´ych syst´emech se nˇekter´epˇrep´ınaˇce mohou liˇsit, napˇr´ıklad ld na Solarisu nezn´apˇrep´ınaˇce -shared a -non shared, je nutn´e pouˇz´ıt jin´e. • u mal´ych program˚u(v jednom souboru) lze prov´est pˇreklad a linkov´an´ı jedn´ım pˇr´ıkazem cc. U vˇetˇs´ıch program˚uskl´adaj´ıc´ıch se z mnoha zdrojov´ych
27 soubor˚ua knihoven se obvykle oddˇeluje pˇreklad a linkov´an´ıa cel´yproces je ˇr´ızen utilitou make.
R´ızen´ıpˇrekladuˇ a linkov´an´ı(make) • zdrojov´etexty main.c util.h util.c #include "util.h" void msg(); #include "util.h" main() msg() { { msg(); puts(); } } • z´avislosti • soubor Makefile main.c prog : main.o util.o ց cc -o prog main.o util.o main.o ր ց main.o : main.c util.h util.h prog cc -c main.c ց ր util.o util.o : util.c util.h ր cc -c util.c util.c
• program je moˇzn´etak´epˇreloˇzit a slinkovat jedn´ım vol´an´ım kompil´atoru, nebo definovat postup pˇrekladu a linkov´an´ıpomoc´ıshellov´eho skriptu. D˚uvodem pro pouˇzit´ı make je to, ˇze vyhodnocuje z´avislosti mezi soubory a po zmˇenˇe nˇekter´eho zdrojov´eho souboru pˇrekl´ad´ajenom to, co na nˇem z´avis´ı. Cast´yˇ zp˚usob pˇrekladu softwaru po aplikov´an´ızmˇen zp˚usobem“make clean; make all” je v situaci, kdy cel´ypˇreklad trv´aminuty (des´ıtky minut, hodiny. . . ), trochu nevhodn´y– pr´avˇeproto je d˚uleˇzit´em´ıt dobˇre napsan´y Makefile. • ˇr´adek “prog : main.o util.o” definuje, ˇze se m´anejprve rekurzivnˇezajistit existence a aktu´alnost soubor˚u main.o a util.o. Pak se zkontroluje, zda soubor (c´ıl) prog existuje a je aktu´aln´ı(datum posledn´ımodifikace souboru je mladˇs´ıneˇz main.o a util.o). Pokud ano, nedˇel´ase nic. Kdyˇzne, provede se pˇr´ıkaz na n´asleduj´ıc´ım ˇr´adku.
• make se spouˇst´ı typicky s parametrem urˇcuj´ıc´ı pˇr´ıˇsluˇsn´yc´ıl (target); pˇri spuˇstˇen´ıbez parametr˚use vezme prvn´ıtarget. Ten typicky b´yv´a all, coˇz vˇetˇsinou podle unixov´ekonvence pˇreloˇz´ıvˇse, co se pˇreloˇzit m´a. N´asleduje pak tˇreba zavol´an´ı make s parametrem install apod. • make je samozˇrejmˇeuniverz´aln´ın´astroj, pouˇziteln´yi jinde neˇzu pˇreklad˚u
28 Syntaxe vstupn´ıho souboru (make)
• popis z´avislost´ıc´ıle: targets :[files ] • prov´adˇen´epˇr´ıkazy:
• pozor na to, ˇze ˇr´adek s pˇr´ıkazem zaˇc´ın´atabul´atorem, nikoliv me- zerami. Kaˇzd´ypˇr´ıkazov´yˇr´adek se prov´ad´ısamostatn´ym shellem, pokud je potˇreba prov´est v´ıce ˇr´adk˚upomoc´ıjednoho shellu, mus´ıse vˇsechny aˇzna po- sledn´ıukonˇcit backslashem (shell je dostane jako jeden ˇr´adek). Viz pˇr´ıklad, ve kter´em dva posledn´ı echo pˇr´ıkazy jsou souˇc´ast´ıjednoho if pˇr´ıkazu, kter´y je spuˇstˇen samostatn´ym shellem:
$ cat Makefile # Makefile test
all: @echo $$$$ @echo $$$$ @if true; then \ echo $$$$; \ echo $$$$; \ fi $ make 5513 5514 5515 5515
• zdvojen´ım $ se potlaˇc´ıspeci´aln´ıv´yznam dolaru (viz n´asleduj´ıc´ıslajd) • znak @ na zaˇc´atku ˇr´adku potlaˇc´ıjeho v´ypis – make jinak standardnˇevypisuje nejdˇr´ıve to, co bude vykon´avat.
29 • znak - na zaˇc´atku ˇr´adku zp˚usob´ıignorov´an´ınenulov´en´avratov´ehodnoty; jinak make vˇzdy v takov´esituaci zahl´as´ıchyby a okamˇzitˇeskonˇc´ı. • test1: false echo "OK"
test2: -false echo "OK"
Makra (make)
• definice makra: name = string • pokraˇcov´an´ıvkl´ad´amezeru • nedefinovan´amakra jsou pr´azdn´a • nez´aleˇz´ına poˇrad´ıdefinic r˚uzn´ych maker • definice na pˇr´ıkazov´eˇr´adce: make target name =string • vyvol´an´ımakra: $name (pouze jednoznakov´e name ), ${name } nebo $(name ) • syst´emov´epromˇenn´ejsou pˇr´ıstupn´ejako makra
• kdyˇzje stejn´emakro definov´ano v´ıcekr´at, plat´ıposledn´ıdefinice. • makra nen´ımoˇzn´edefinovat rekurzivnˇe.
$ cat Makefile M=value1 M=$(M) value2 all: echo $(M) $ make Variable M is recursive.
• ˇcasto se pouˇz´ıvaj´ır˚uzn´erozˇs´ıˇren´everze make (napˇr. GNU, BSD), kter´eum´ı, podm´ınˇen´esekce v Makefile, redefinice promˇenn´ych, apod. • napsat Makefile kter´ybude fungovat najednou pro r˚uzn´everze make nemus´ı b´yt jednoduch´e, proto existuj´ıprojekty jako je napˇr. GNU automake. Pro jed- noduch´ypodm´ıneˇcn´ypˇreklad v z´avislosti na syst´emu a kde se daj´ıoˇcek´avat
30 r˚uzn´everze pˇr´ıkazu make, je moˇzn´epouˇz´ıt napˇr´ıklad n´asleduj´ıc´ık´od, kter´y mi fungoval na vˇsech v nˇem zm´ınˇen´ych syst´emech (znak ‘ je zpˇetn´auvozovka, a ’ je norm´aln´ıuvozovka):
CFLAGS=‘x=\‘uname\‘; \ if [ $${x} = FreeBSD ]; then \ echo ’-Wall’; \ elif [ $${x} = SunOS ]; then \ echo ’-v’; \ elif [ $${x} = Linux ]; then \ echo ’-Wall -g’; \ fi‘
all: @echo "$(CFLAGS)"
• v ostatn´ıch situac´ıch je vhodn´e, pˇr´ıpadnˇenezbytn´e pouˇz´ıt programy typu autoconf nebo automake • make je velmi siln´yn´astroj, staˇc´ıse pod´ıvat do syst´emov´ych Makefile sou- bor˚ujak´ehokoli Unixov´eho syst´emu. Typickou spoleˇcnou vlastnost´ıje to, ˇze neexistuje dokumentace jak je dan´ymakefile framework postaven.
Dynamick´ylinker
Pˇri pˇrekladu je nutn´em´ıt vˇsechny potˇrebn´edynamick´eknihovny, protoˇze se kontroluje dosaˇzitelnost pouˇzit´ych symbol˚u, sestaven´ı kompletn´ıho programu se ale provede aˇzpˇri spuˇstˇen´ı. To je ´ukol pro dynamick´ylinker (run-time linker, loader). • seznam dynamick´ych knihoven zjist´ıze sekce .dynamic • syst´em m´anastaveno nˇekolik cest, kde se automaticky tyto knihovny hledaj´ı • v sekci .dynamic je moˇzn´edalˇs´ıcesty ke knihovn´am pˇridat pomoc´ıtag˚u RUNPATH/RPATH • nalezen´eknihovny se pˇripoj´ıdo pamˇet’ov´eho procesu pomoc´ı vol´an´ı mmap() (bude pozdˇeji)
Nasleduj´ıc´ıpˇr´ıkazy a pˇr´ıklady se t´ykaj´ıSolarisu. Pokud to nebude fungo- vat na jin´ych syst´emech, tak maj´ıekvivaletn´ın´astroje s podobnou funkcionalitou.
• proces spuˇstˇen´ıdynamicky slinkovan´eho programu prob´ıh´atak, ˇze kernel ve vol´an´ı exec() namapuje dan´yprogram do pamˇeti a zjist´ı, jak´ydynamick´ylin- ker se m´apouˇz´ıt (viz d´ale). Pˇred t´ım, neˇzj´adro pˇred´alinkeru kontrolu, linker
31 namapuje do pamˇet’ov´eho prostoru spouˇstˇen´eho procesu. Linker z hlaviˇcky programu zjist´ı, jak´edynamick´eknihovny se maj´ıd´ale namapovat, provede to a teprve pak pˇred´aˇr´ızen´ıvaˇsemu programu. V´aˇsprogram m˚uˇze za bˇehu d´ale vyuˇz´ıvat dynamick´ylinker pomoc´ıvol´an´ıtypu dlopen() a spol. (k tomu se tak´edostaneme pozdˇeji). Uvˇedomte si, ˇze dynamick´y linker zde nepracuje jako samostatn´yproces, jeho k´od se pouˇz´ıv´av r´amci pamˇet’ov´eho prostoru vaˇseho procesu; v´aˇsprogram, linker a knihovny dohromady tvoˇr´ıjeden pro- ces. • seznam sekc´ı se zjist´ı pomoc´ı elfdump -c (GNU m´apˇr´ıkaz readelf). O programov´ych sekc´ıch bude v´ıce na stranˇe115. • jak´ydynamick´ylinker se pouˇzije kernel zjist´ıze sekce .interp,viz ”elfdump -i”a“ld -I”. To znamen´a, ˇze si m˚uˇzete napsat vlastn´ılinker a pomoc´ı -I pro ld ho pak nastavit jako dynamick´ylinker pro v´aˇsprogram. • dynamick´asekce se vyp´ıˇse pomoc´ı elfdump -d, dynamick´eknihovny jsou oznaˇcen´etagem NEEDED • z´avislosti na dynamick´ych knihovn´ach je moˇzn´edobˇre zjistit pomoc´ıpˇr´ıkazu ldd, kter´yzjist´ıkonkr´etn´ıcesty ke knihovn´am. Tento pˇr´ıkaz ˇreˇs´ız´avislosti rekurz´ıvnˇe, tj. uvid´ıte tedy i nepˇr´ım´ez´avislosti - tj. takov´eknihovny, kter´e jsou pouˇzit´eknihovnami, kter´epˇr´ısluˇsn´yprogram pouˇz´ıv´apˇr´ımo. Zjistit co je pˇresnˇez´avisl´ena ˇcem je moˇzn´epomoc´ıvolby -v. • jak´eknihovny byly pˇri spuˇstˇen´ınakonec pouˇzity m˚uˇze b´yt jin´eneˇzco uk´aˇze pˇr´ıkaz ldd, a to tˇreba d´ıky mechanismu LD PRELOAD, na Solarisu proto exis- tuje pˇr´ıkaz pldd, kter´ypomoc´ıˇc´ısla procesu uk´aˇze z´avislosti konkr´etn´ıho spuˇstˇen´eho programu. • v´ıce viz manu´alov´astr´anka pro dynamick´ylinker v Solarisu, ld.so.1, pˇr´ıpad- nˇe Linker and Libraries Guide na docs.sun.com. Na FreeBSD se dynamick´y linker naz´yv´a ld-elf.so.1, na Linuxu ld-linux.so.1, na IRIXu rld atd. • dynamick´ylinker se typicky d´akonfigurovat pomoc´ınastaven´ıpromˇenn´ych, napˇr´ıklad si zkuste na Solarisu spustit toto:
LD_LIBRARY_PATH=/tmp LD_DEBUG=libs,detail date
a pro vˇsechny moˇznosti jak debugovat dynamick´ylinker pouˇzijte:
LD_DEBUG=help date
• jin´ypˇr´ıklad, kdy linker hled´aknihovny i jinde neˇzv defaultn´ıch adres´aˇr´ıch:
$ cp /lib/libc.so.1 /tmp $ LD_LIBRARY_PATH=/tmp sleep 100 & [1] 104547 $ pldd 104547 104547: sleep 100 /tmp/libc.so.1 /usr/lib/locale/cs_CZ.ISO8859-2/cs_CZ.ISO8859-2.so.3
32 API vers ABI
API – Application Programming Interface • rozhran´ıpouˇzit´epouze ve zdrojov´em k´odu • rozhran´ı zdroj´aku v˚uˇci syst´emu, knihovnˇeˇci vlastn´ımu k´odu, tj. napˇr. exit(1), printf("hello\n") nebo my function(1, 2) • ...aby se stejn´y zdrojov´ytext mohl pˇreloˇzit na vˇsech syst´emech podporuj´ıc´ıdan´eAPI ABI – Application Binary Interface • low-level rozhran´ı aplikace v˚uˇci syst´emu, knihovnˇeˇci jin´eˇc´asti sama sebe • ...aby se objektov´ymodul mohl pouˇz´ıt vˇsude tam, kde je podporov´ano stejn´eABI
• pˇr´ıkladem API je tˇreba API definovan´enormou POSIX.1 • ABI definuje konvenci vol´an´ı(to jak program pˇred´aparametry funkci a jak od n´ıpˇrevezme n´avratovou hodnotu), jak´ajsou ˇc´ısla syst´emov´ych vol´an´ı, jak se syst´emov´evol´an´ıprovede ˇci form´at objektov´eho modulu ˇci pˇrij´ıman´ych argument˚u, viz pˇr´ıklad dole. • ABI knihovny pak definuje mimo jin´emnoˇzinu vol´an´ıkter´a jsou knihovnou definov´ana, jejich parametry a typy tˇechto parametr˚u • n´asledn´auk´azka je pˇr´ıklad na to, kdy v´yvoj´aˇrzmˇen´ıvelikost argument˚uv baj- tech (tj. zmˇen´ıABI knihovny), a nahrad´ınovou verz´ıtu starou. Vˇsimnˇete si, ˇze dynamick´ylinker toto nezjist´ı; nem´atotiˇzjak, ˇr´ıd´ıse podle jm´ena knihovny v dynamick´esekci programu, a to se nezmˇenilo. Uveden´azmˇena je sice i zmˇena v API a probl´em by se odstranil, kdybychom main.c znovu pˇreloˇzili se zmˇenˇen´ym ˇr´adkem deklarace funkce add(). To je ale ˇcasto probl´em (pˇre- kl´adejte cel´ysyst´em jen kv˚uli tomu), proto je tak d˚uleˇzit´edodrˇzovat zpˇetnou kompatibilitu v ABI u knihoven. V´ysledek n´asleduj´ıc´ıho pˇrekladu knihovny, programu a jeho spuˇstˇen´ıje jak bychom oˇcek´avali (pouˇzit cc ze SunStudio, pro gcc pouˇzijte m´ısto -G volbu -shared; novˇejˇs´ı gcc nav´ıc neznaj´ı -R a je m´ısto toho nutn´epouˇz´ıt -Xlinker -R -Xlinker .:
$ cat main.c int my_add(int a, int b);
int main(void)
33 { printf("%d\n", my_add(128, 1)); return (0); }
$ cat add.c int my_add(int a, int b) { return (a + b); }
$ cc -G -o libadd.so add.c $ cc -L. -ladd -R. main.c $ ./a.out 129
Nyn´ıale pˇriˇsla dalˇs´ıverze knihovny se stejn´ym jm´enem, a ve funkci add() nastala zmˇena v typu argument˚u. Program ale o niˇcem nev´ı, nech´ase spustit a vr´at´ıchybnou hodnotu:
$ cat add2.c int my_add(char a, char b) { return (a + b); }
$ cc -G -o libadd.so add2.c $ ./a.out -127
• zde pak pˇrich´az´ıke slovu verzov´an´ıknihoven, tj. je nutn´e“nˇeco” zmˇenit tak, aby po instalaci nov´eknihovny neˇslo program spustit bez jeho rekompilace.
34 Debugger dbx
• Vol´an´ı: dbx [ options ][ program [ core ]] • Nejbˇeˇznˇejˇs´ıpˇr´ıkazy: run [arglist ] start programu where vypiˇsz´asobn´ık print expr vypiˇsv´yraz set var = expr zmˇeˇnhodnotu promˇenn´e cont pokraˇcov´an´ıbˇehu programu next, step proved’ ˇr´adku (bez/s vnoˇren´ım do funkce) stop condition nastaven´ıbreakpointu trace condition nastaven´ıtracepointu command n akce na breakpointu (pˇr´ıkazy n´asleduj´ı) help [name ] n´apovˇeda quit ukonˇcen´ıdebuggeru
• z´akladn´ıˇr´adkov´ysymbolick´ydebugger, aby bylo moˇzn´eho plnˇevyuˇz´ıt, mus´ı b´yt program pˇreloˇzen s ladic´ımi informacemi (cc -g). Ladˇen´yprogram se startuje z debuggeru pˇr´ıkazem run, nebo se debugger pˇripoj´ık jiˇzbˇeˇz´ıc´ımu procesu. Pomoc´ı dbx lze analyzovat i havarovan´yprogram, kter´yvygeneroval soubor core. • je moˇzn´eho naj´ıt napˇr. na Solarisu, na Linuxu a FreeBSD defaultnˇenen´ı. • pro debugging se zdrojov´ymi k´ody nestaˇc´ıpouˇz´ıt volbu -g, je z´aroveˇnnutn´e m´ıt i zdroj´aky a objektov´emoduly tam, kde byly pˇri pˇrekladu. To je typicky bˇeˇzn´asituace, protoˇze lad´ıte na stroji, kde z´aroveˇn i vyv´ıj´ıte. Pokud tomu tak nen´ı, je nutn´esi zdroj´aky a objektov´emoduly zajistit, pokud k nim vede jin´acesta, lze pouˇz´ıt dbx pˇr´ıkaz pathmap. • gdb-kompatibiln´ım´od se spust´ı pˇres gdb on. Pokud v´as zaj´ım´a, jak´ym´a dbx ekvivalentn´ıpˇr´ıkaz ke konkr´etn´ımu gdb pˇr´ıkazu, pom˚uˇze v´am help FAQ; hned prvn´ıot´azka je “A.1 Gdb does
35 GNU debugger gdb
• Vol´an´ı: gdb [ options ][ program [ core ]] • Nejbˇeˇznˇejˇs´ıpˇr´ıkazy: run [arglist ] start programu bt vypiˇsz´asobn´ık print expr vypiˇsv´yraz set var = expr zmˇeˇnhodnotu promˇenn´e cont pokraˇcov´an´ıbˇehu programu next, step proved’ ˇr´adku (bez/s vnoˇren´ım do funkce) break condition nastaven´ıbreakpointu help [name ] n´apovˇeda quit ukonˇcen´ıdebuggeru
• GNU obdoba dbx. M´od kompatibiln´ıs dbx spust´ıte pˇres -dbx. • na r˚uzn´ych platform´ach existuj´ıi debuggery s grafick´ym rozhran´ım, napˇr. debugger (Solaris), cvd (IRIX), xxgdb (GNU), ddd (GNU). Castoˇ funguj´ı jako nadstavby nad dbx, gdb. • #include
Breakpoint 1, main () at main.c:4 4 printf("hello, world\n"); (gdb) next hello, world 5 return0; (gdb) c Continuing. Program exited normally. (gdb) q • debuggery jsou v´yborn´ymi pomocn´ıky pokud v´aˇsprogram konˇc´ına chyby
36 typu “segmentation error” – tj. kdyˇzzkus´ıte nekorektnˇe pˇristoupit do pamˇeti, napˇr´ıklad tam kde nem´ate co dˇelat. Kdyˇzpˇri pˇrekladu pouˇzijete option -g, uk´aˇze v´am pak debugger pˇresnˇeˇc´ıslo ˇr´adku, kde nastal probl´em. Konkr´etn´ı pˇr´ıklad (proˇcse vlastnˇetento program chov´ajak se chov´a??? Hint: zkuste pˇreloˇzit na Solarisu pˇrekladaˇcem cc a spustit):
$ cat -n main.c 1 int 2 main(void) 3 { 4 char*c="heyworld"; 5 c[0]=’\0’; 6 return(0); 7 } } $ gcc -g main.c $ ./a.out Bus error (core dumped) $ gdb a.out a.out.core ... Core was generated by ‘a.out’. Program terminated with signal 10, Bus error. ... #0 0x080484e6 in main () at main.c:5 5 c[0]=’\0’;
Obsah
• ´uvod, v´yvoj UNIXu a C, program´atorsk´en´astroje • z´akladn´ıpojmy a konvence UNIXu a jeho API • pˇr´ıstupov´apr´ava, perifern´ızaˇr´ızen´ı, syst´em soubor˚u • manipulace s procesy, spouˇstˇen´ıprogram˚u • sign´aly • synchronizace a komunikace proces˚u • s´ıt’ov´akomunikace • vl´akna, synchronizace vl´aken • ??? - bude definov´ano pozdˇeji, podle toho kolik zbyde ˇcasu
37 Standardn´ıhlaviˇckov´esoubory (ANSI C)
stdlib.h . . . z´akladn´ımakra a funkce errno.h . . . oˇsetˇren´ıchyb stdio.h . . . vstup a v´ystup ctype.h ... pr´ace se znaky string.h ... pr´ace s ˇretˇezci time.h ... pr´ace s datem a ˇcasem math.h . . . matematick´efunkce setjmp.h . . . dlouh´eskoky assert.h . . . ladic´ıfunkce stdarg.h . . . pr´ace s promˇenn´ym poˇctem parametr˚u limits.h . . . implementaˇcnˇez´avisl´ekonstanty signal.h . . . oˇsetˇren´ısign´al˚u
• hlaviˇckov´ysoubor (header file) je soubor s deklaracemi funkc´ı(forward decla- ration), promˇenn´ych a maker. Z pohledu preprocesoru je to obyˇcejn´ysoubor napsan´yv jazyce C.
• pozor na to, ˇze tyto hlaviˇckov´esoubory nejsou specifick´e pro UNIX. Jsou souˇc´ast´ı standardu ANSI C, kter´yjak jiˇzv´ıme (strana 13), je zahrnut v POSIX.1. • pˇr´ısluˇsn´yhlaviˇckov´ysoubor pro konkr´etn´ıfunkci najdete v manu´alov´estr´ance dan´efunkce, toto je zaˇc´atek manu´alov´estr´anky na Solarisu pro memcpy():
StandardCLibraryFunctions memory(3C)
NAME memory, memccpy, memchr, memcmp, memcpy, memmove, memset - memory operations
SYNOPSIS #include
• jednotliv´amakra obsaˇzen´av tˇechto souborech vˇetˇsinou nejsou vysvˇetlena, v´yznam jednotliv´ych maker je ale moˇzn´esi vyhledat v pˇr´ısluˇsn´ych specifi- kac´ıch, kter´ejsou on-line. Na nˇekter´ych syst´emech (Solaris) maj´ıjednotliv´e hlaviˇckov´esoubory svoji vlastn´ımanu´alovou str´anku (man stdlib.h). • makro assert() je moˇzn´ez bˇehem kompilace odstranit pomoc´ımakra NDEBUG
38 Standardn´ıhlaviˇckov´esoubory (2)
unistd.h . . . nejpouˇz´ıvanˇejˇs´ısyst´emov´avol´an´ı sys/types.h . . . datov´etypy pouˇz´ıvan´ev API UNIXu fcntl.h . . . ˇr´ıd´ıc´ıoperace pro soubory sys/stat.h ... informace o souborech dirent.h . . . proch´azen´ıadres´aˇr˚u sys/wait.h . . . ˇcek´an´ına synovsk´eprocesy sys/mman.h . . . mapov´an´ıpamˇeti curses.h . . . ovl´ad´an´ıtermin´alu regex.h . . . pr´ace s regul´arn´ımi v´yrazy
• tyto headery uˇzpatˇr´ıdo UNIXu. • zaj´ımav´em˚uˇze b´yt pod´ıvat se do sys/types.h
39 Standardn´ıhlaviˇckov´esoubory (3)
semaphore.h . . . semafory (POSIX) pthread.h . . . vl´akna (POSIX threads) sys/socket.h . . . s´ıt’ov´akomunikace arpa/inet.h . . . manipulace se s´ıt’ov´ymi adresami sys/ipc.h ... spoleˇcn´edeklarace pro System V IPC sys/shm.h . . . sd´ılen´apamˇet’ (System V) sys/msg.h . . . fronty zpr´av (System V) sys/sem.h . . . semafory (System V)
• dokonˇcen´ı nejd˚uleˇzitˇejˇs´ıch UNIXov´ych header˚u. Existuj´ı samozˇrejmˇejeˇstˇe dalˇs´ı.
40 Funkce main()
• pˇri spuˇstˇen´ıprogramu je pˇred´ano ˇr´ızen´ıfunkci main(). • int main (int argc, char *argv []); – argc . . . poˇcet argument˚upˇr´ıkazov´eˇr´adky – argv . . . pole argument˚u ∗ podle konvence je argv[0] cesta k programu ∗ posledn´ıprvek je argv[argc] == NULL – n´avrat z main() nebo vol´an´ı exit() ukonˇc´ıprogram – standardn´ın´avratov´ehodnoty EXIT_SUCCESS (0) a EXIT_FAILURE (1)
ls-l/ argv[0] "ls" argv[1] "-l" argc 3 argv[2] argv argv[3] "/"
• prvn´ı parametr (typu int) ud´av´apoˇcet argument˚una pˇr´ıkazov´em ˇr´adku (vˇcetnˇeparametru 0 – jm´ena programu) a druh´yparametr (typu char**) je pole ukazatel˚una tyto ˇretˇezce. Za posledn´ım ˇretˇezcem je jeˇstˇe NULL pointer – a to je nˇeco jin´eho neˇzpr´azdn´yˇretˇezec. • pˇri spuˇstˇen´ıprogramu pˇred´ak´od dynamick´eho linkeru ˇr´ızen´ıfunkci main(), viz strana 31. Staticky slinkovan´emu programu se ˇr´ızen´ı pˇred´apˇr´ımo. Nepˇr´ıtomnost main() v programu zp˚usob´ı chybu pˇri pˇrekladu na ´urovni linkeru. T´eto funkci se pˇred´ajm´eno spuˇstˇen´eho programu, argumenty z pˇr´ıkazov´eˇr´adky a pˇr´ıpadnˇei promˇenn´eprostˇred´ı. Ukonˇcen´ıt´eto funkce znamen´akonec pro- gramu a n´avratov´ahodnota se pouˇzije jako k´od ukonˇcen´ı programu pro OS. Jinou moˇznost´ıukonˇcen´ıprogramu je pouˇzit´ıfunkce exit() nebo _exit(), kterou lze pouˇz´ıt kdykoliv, nejen ve funkci main(). V C lze pouˇz´ıvat obˇe metody ukonˇcen´ıprogramu. • pˇred´an´ıpromˇenn´ych prostˇred´ıtˇret´ım parametrem typu char** nen´ısouˇc´ast´ı normativn´ıˇc´asti C standardu, pouze informativn´ı. Pˇrekladaˇce to ale typicky podporuj´ı. Varianta main() s promˇenn´ymi prostˇred´ıpak vypad´atakto: int main(int argc, char *argv [], char *envp []); • n´avratov´ytyp funkce main by mˇel b´yt vˇzdy int; pˇrekladaˇcsi jinak bude stˇeˇzovat. Z t´eto hodnoty se ale pouˇzije pouze nejniˇzˇs´ıch 8 bit˚u. Pozor na to, ˇze na rozd´ıl od jazyka C n´avratov´ahodnota 0 m´av shellu v´yznam true (´uspˇech) a nenula v´yznam false (ne´uspˇech). • rozd´ıl mezi funkcemi exit() a _exit() je v tom, ˇze exit() pˇred ukonˇcen´ım programu jeˇstˇezavˇre streamy stdio a vol´afunkce zaregistrovan´epomoc´ı atexit(). V z´avislosti na syst´emu to mohou b´yt i dalˇs´ıakce. Napˇr´ıklad ve FreeBSD je exit() syst´emov´evol´an´ıa exit() knihovn´ıfunkce. V Solarisu jsou obˇesyst´emov´ymi vol´an´ımi.
41 Promˇenn´eprostˇred´ı
• seznam vˇsech promˇenn´ych prostˇred´ı(environment variables) se pˇred´av´ajako promˇenn´a extern char **environ; • je to pole ukazatel˚u(ukonˇcen´eNULL) na ˇretˇezce ve tvaru: promˇenn´a =hodnota environ
environ[0] "SHELL=/bin/bash" environ[1] "DISPLAY=:0" environ[2] environ[3] "LOGNAME=beran"
• shell pˇred´av´aspuˇstˇen´emu programu ty promˇenn´e, kter´ejsou oznaˇceny jako exportovan´e(Bourne-like shellech pˇr´ıkazem export variable ). Po zmˇenˇe obsahu jiˇzjednou exportovan´epromˇenn´esamozˇrejmˇenen´ıpotˇreba promˇennou znovu exportovat. Pˇr´ıkazem env v´am shell vyp´ıˇse aktu´aln´ıpromˇenn´eprostˇred´ı, a pˇridat promˇennou do prostˇred´ıspouˇstˇen´eho programu pak staˇc´ıprov´est na pˇr´ıkazov´eˇr´adce, aniˇzbyste museli mˇenit prostˇred´ıvaˇseho shellu:
$ date Sun Oct 7 13:13:58 PDT 2007 $ LC_TIME=fr date dimanche 7 octobre 2007 13 h 14 PDT
• pˇri nahrazen´ıaktu´aln´ıho obrazu procesu obrazem jin´ym se pˇred´av´a, pokud se neˇrekne jinak, synovsk´ym proces˚um cel´epole environ automaticky. Je moˇzn´eve vol´an´ıpˇr´ısluˇsn´evarianty funkce exec pˇredat pole jin´e. • jak´epromˇenn´eprostˇred´ıkonkr´etn´ıpˇr´ıkaz pouˇz´ıv´a(a jak je pouˇz´ıv´a) by mˇelo b´yt v manu´alov´estr´ance. Typicky v sekci nazvan´e ENVIRONMENT nebo ENVIRONMENT VARIABLES • man napˇr´ıklad pouˇz´ıv´a PAGER, vipw pak promˇennou EDITOR apod. • pokud je envp tˇret´ım parametrem funkce main, tak je to stejn´ahodnota co je v ukazatelu environ.
42 Manipulace s promˇenn´ymi prostˇred´ı
• je moˇzn´epˇr´ımo zmˇenit promˇennou environ • char *getenv (const char *name ); – vr´at´ıhodnotu promˇenn´ename • int putenv (char *string ); – vloˇz´ıstring ve tvaru jm´eno =hodnota do prostˇred´ı(pˇrid´a novou nebo modifikuje existuj´ıc´ıpromˇennou) • zmˇeny se pˇren´aˇsej´ıdo synovsk´ych proces˚u • zmˇeny v prostˇred´ısyna samozˇrejmˇeprostˇred´ıotce neovlivn´ı • existuj´ıi funkce setenv() a unsetenv()
• u putenv() se vloˇzen´yˇretˇezec stane souˇc´ast´ıprostˇred´ı(jeho pozdˇejˇs´ızmˇena tak zmˇen´ıprostˇred´ı) a nesm´ıte proto pouˇz´ıvat retˇezce v automatick´ych promˇenn´ych, toto ˇreˇs´ı setenv(), kter´yhodnotu promˇenn´ezkop´ıruje
• d˚uleˇzit´eje zapamatovat si, ˇze synovsk´yproces zdˇed´ı v okamˇziku sv´eho vzniku od rodiˇce vˇsechny promˇenn´eprostˇred´ı, ale jak´akoliv manipulace s nimi v synovi je lok´aln´ıa do otce se nepˇren´aˇs´ı. Kaˇzd´yproces m´asvou kopii pro- mˇenn´ych, proto ani n´asledn´azmˇena prostˇred´ı otce nezmˇen´ı promˇenn´ejiˇz existuj´ıc´ıho potomka. • dalˇs´ırozd´ıl mezi putenv a setenv je ten, ˇze v setenv mohu definovat, zda existuj´ıc´ıpromˇennou chci nebo nechci pˇrepsat. putenv vˇzdy pˇrepisuje. • int main(void) { printf("%s\n", getenv("USER")); return 0; } $ ./a.out jp
• jelikoˇzv´ıte, ˇze promˇenn´a environ je obyˇcejn´epole ukazatel˚una ˇretˇezce, m˚uˇzete s timto polem pracovat pˇr´ımo. Pozor vˇsak na to, ˇze v takov´em pˇr´ıpadˇepak jiˇznesm´ıte pouˇz´ıvat zde uveden´efunkce, jinak se m˚uˇzete do- stat do probl´em˚us jejich konkr´etn´ıimplementac´ı.
43 Zpracov´an´ıargument˚uprogramu
• obvykl´yz´apis v shellu: program -pˇrep´ınaˇce argumenty • pˇrep´ınaˇce tvaru -x nebo -x hodnota , kde x je jedno p´ısmeno nebo ˇc´ıslice, hodnota je libovoln´yˇretˇezec • nˇekolik pˇrep´ınaˇc˚ulze slouˇcit dohromady: ls -lRa • argument ’--’ nebo prvn´ıargument nezaˇc´ınaj´ıc´ı’-’ ukonˇcuje pˇrep´ınaˇce, n´asleduj´ıc´ıargumenty nejsou povaˇzov´any za pˇrep´ınaˇce, i kdyˇzzaˇc´ınaj´ıznakem ’-’. • tento tvar argument˚upoˇzaduje norma a lze je zpracov´avat automaticky funkc´ı getopt().
• argumenty lze samozˇrejmˇezpracov´avat vlastn´ıfunkc´ı, ale standardn´ıfunkce je pohodlnˇejˇs´ı. • argumenty se typicky mohou opakovat, ale to m´asmysl jen v nˇekter´ych si- tuac´ıch • poˇrad´ıpˇrep´ınaˇc˚um˚uˇze b´yt d˚uleˇzit´ea je na aplikaci, aby toto specifikovala • UNIX norma definuje pomoc´ı13 pravidel velmi pˇresnˇe, jak by mˇely vypa- dat n´azvy pˇr´ıkaz˚ua form´at pˇrep´ınaˇc˚u. Napˇr´ıklad jm´eno pˇr´ıkazu by mˇelo b´yt pouze mal´ymi p´ısmeny, dlouh´e2–9 znak˚u, z pˇrenositeln´eznakov´esady. Pˇrep´ınaˇce bez argument˚uby mˇelo b´yt moˇzn´ed´at do skupiny za jedn´ım zna- kem ’–’. Atd. • pouˇz´ıvat ˇc´ıslice jako pˇrep´ınaˇce je zastaral´e; je to nˇekde v normˇeUNIX 03, i kdyˇzj´ato v n´ınenaˇsel. • pozor na Linux a jeho (ponˇekud zvl´aˇstn´ıa nestandardn´ı) permutov´an´ıargu- ment˚u(viz dalˇs´ıslidy). • pˇrep´ınaˇc -W by mˇel b´yt rezervovan´ypro vendor options, tj. pro nepˇrenositeln´a rozˇs´ıˇren´ı
44 Zpracov´an´ıpˇrep´ınaˇc˚u: getopt() int getopt(int argc, char *const argv [], const char *optstring); extern char *optarg ; extern int optind, opterr, optopt ; • funkce dostane parametry z pˇr´ıkazov´eho ˇr´adku, pˇri kaˇzd´em vol´an´ızpracuje a vr´at´ıdalˇs´ıpˇrep´ınaˇc. Pokud m´a pˇrep´ınaˇc hodnotu, vr´at´ıji v optarg. • kdyˇzjsou vyˇcerp´any vˇsechny pˇrep´ınaˇce, vr´at´ı-1 a v optind je ˇc´ıslo prvn´ıho nezpracovan´eho argumentu. • moˇzn´epˇrep´ınaˇce jsou zad´any v optstring, kdyˇzza znakem pˇrep´ınaˇce n´asleduje ’:’, m´apˇrep´ınaˇcpovinnou hodnotu. • pˇri chybˇe(nezn´am´ypˇrep´ınaˇc, chyb´ıhodnota) vr´at´ı’?’, uloˇz´ıznak pˇrep´ınaˇce do optopt a kdyˇz opterr nebylo nastaveno na nulu, vyp´ıˇse chybov´ehl´aˇsen´ı.
• obvykle se nejprve pomoc´ı getopt() naˇctou pˇrep´ınaˇce a pak se vlastn´ımi prostˇredky zpracuj´ıostatn´ıargumenty (ˇcasto jsou to jm´ena soubor˚u). • je konvenc´ı, ˇze volby v parametru optstring jsou setˇr´ıdˇen´e.
45 Pˇr´ıklad pouˇzit´ı getopt()
struct { int a, b; char c[128]; } opts; int opt; char *arg1;
while((opt = getopt(argc, argv, "abc:")) != -1) switch(opt) { case ’a’: opts.a = 1; break; case ’b’: opts.b = 1; break; case ’c’: strcpy(opts.c, optarg); break; case ’?’: fprintf(stderr, "usage: %s [-ab] [-c Carg] arg1 arg2 ...\n", basename(argv[0])); break; } arg1 = argv[optind];
• dobr´ym zvykem je pˇri detekov´an´ınezn´am´eho pˇrep´ınaˇce (nebo ˇspatn´eho z´a- pisu parametr˚uprogramu) vypsat struˇcnou n´apovˇedu (pˇr´ıpadnˇes odkazem na podrobnˇejˇs´ıdokumentaci) a ukonˇcit program s chybou, tj. s nenulovou n´avratovou hodnotou. • pˇr´ıklad tak´eukazuje nebezpeˇcn´epouˇzit´ıfunkce strcpy() • z pouˇzit´ıfunkce getopt() je vidˇet, ˇze je stavov´a. Zpracovat dalˇs´ıpole ar- gument˚u, pˇr´ıpadnˇeznovuzpracovat p˚uvodn´ı, je moˇzn´enastaven´ım extern´ı promˇenn´e optreset na 1. • standardn´ı getopt() zachov´apoˇrad´ıpˇrep´ınaˇc˚upˇri zpracov´an´ı
• pˇri pouˇzit´ı nedefinovan´eho pˇrep´ınaˇce funkce vyp´ıˇse chybu; to lze potlaˇcit nastaven´ım opterr na 0.
46 Dlouh´ytvar pˇrep´ınaˇc˚u • poprv´ese objevilo v GNU knihovnˇe libiberty: --jm´eno nebo --jm´eno=hodnota • argumenty se permutuj´ıtak, aby pˇrep´ınaˇce byly na zaˇc´atku, napˇr. ls * -l je tot´eˇzjako ls -l *, standardn´ıchov´an´ılze doc´ılit nastaven´ım promˇenn´e POSIXLY_CORRECT. • zpracov´avaj´ıse funkc´ı getopt long(), kter´apouˇz´ıv´apole struktur popisuj´ıc´ıch jednotliv´epˇrep´ınaˇce: struct option { const char *name; /* jm´eno pˇrep´ınaˇce */ int has arg; /* hodnota: ano, ne, volitelnˇe */ int *flag; /* kdyˇzje NULL, funkce vrac´ı val, jinak vrac´ı0 a d´a val do *flag */ int val; /* n´avratov´ahodnota */ };
verze jak se objevila ve FreeBSD (funkce getopt long() nen´ıstandarizovan´a), m´an´asleduj´ıc´ıvlastnosti:
• pokud vˇsechny dlouh´epˇrep´ınaˇce maj´ınastaveny kr´atkou variantu ve val, je chov´an´ı getopt long() kompatibiln´ıs getopt() • je moˇzn´ezad´avat argument k dlouh´emu pˇrep´ınaˇci i s mezerou (napˇr´ıklad --color green) • pokud je nastaven flag, tak getopt long() vrac´ı 0, ˇc´ımˇzse tyto dlouh´e pˇrep´ınaˇce bez kr´atk´evarianty zpracuj´ıv jedn´evˇetvi pˇr´ıkazu case • existuje i vol´an´ı getopt long only(), kter´epovoluje i dlouh´epˇrep´ınaˇce uvo- zen´ejednou uvozovkou (-option) • funkci getopt long() je moˇzn´epouˇz´ıvat dvˇemi zp˚usoby. Prvn´ızp˚usob je, ˇze kaˇzd´ydlouh´ypˇrep´ınaˇcm´akoresponduj´ıc´ıkr´atk´y – takto lze jednoduˇse pˇridat dlouh´epˇrep´ınaˇce do existuj´ıc´ıho programu a je kompatibiln´ı s getopt. Druh´yzp˚usob umoˇzˇnuje m´ıt samostatn´edlouh´epˇrep´ınaˇce. V tom pˇr´ıpadˇe funkce vrac´ıvˇzdy 0 (nekompatibilita s getopt) a promˇenn´a *flag se nastav´ı na val. • na konkr´etn´ım pˇr´ıkladu na n´asleduj´ıc´ıstr´ance je vidˇet, jak to cel´efunguje
47 Dlouh´epˇrep´ınaˇce (pokraˇcov´an´ı)
int getopt long(int argc, char * const argv [], const char *optstring, const struct option *longopts, int *longindex ); • optstring obsahuje jednop´ısmenn´epˇrep´ınaˇce, longopts obsahuje adresu pole struktur pro dlouh´epˇrep´ınaˇce (posledn´ı z´aznam pole obsahuje sam´enuly) • pokud funkce naraz´ına dlouh´ypˇrep´ınaˇc, vrac´ıodpov´ıdaj´ıc´ı val nebo nulu (pokud flag nebyl NULL), jinak je chov´an´ıshodn´es getopt(). • do *longindex (kdyˇznen´ı NULL) d´anav´ıc -1 nalezen´eho pˇrep´ınaˇce v longopts.
• toto je upraven´ypˇr´ıklad z manu´alov´estr´anky na FreeBSD:
#include
int ch, fd, daggerset, bflag = 0;
static struct option longopts[] = { { "buffy", no_argument, NULL, ’b’ }, { "fluoride", required_argument, NULL, ’f’ }, { "daggerset", no_argument, &daggerset, 1 }, { NULL, 0, NULL, 0 }};
int main(int argc, char **argv) { while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1) switch (ch) { case ’b’: bflag = 1; break; case ’f’: if ((fd = open(optarg, O_RDONLY, 0)) == -1) printf("unable to open %s", optarg); break; case 0: if (daggerset) { printf("Buffy will use her dagger to " "apply fluoride to dracula’s teeth\n"); } break; default: printf("usage: ...\n"); } argc -= optind; argv += optind; return 0; }
48 Struktura klasick´eho OS UNIX
uˇzivatelsk´yproces uˇzivatelsk´y pˇreruˇsen´ı n´avrat reˇzim
rozhran´ıvol´an´ıj´adra reˇzim subsyst´em j´adra ˇr´ızen´ısoubor˚u
buffery subsyst´em IPC ˇr´ızen´ı pl´anovaˇc znakov´e blokov´e proces˚u pˇridˇelov´an´ı ovladaˇce a pamˇeti pamˇeti
strojovˇez´avisl´avrstva ovl´ad´an´ıhardware
hardware
• toto sch´ema je pˇrevzato z [Bach86], viz literatura. Zd˚urazˇnuje dva ´ustˇredn´ı pojmy v modelu syst´emu UNIX – soubory a procesy. V praxi se j´adro od modelu typicky odliˇsuje, ale zde je d˚uleˇzit´az´akladn´ı pˇredstava. • UNIX rozliˇsuje dva reˇzimy bˇehu procesoru: uˇzivatelsk´yreˇzim a reˇzim j´adra. V uˇzivatelsk´em reˇzimu nejsou pˇr´ıstupn´eprivilegovan´einstrukce (napˇr. ma- pov´an´ıpamˇeti, I/O, maskov´an´ıpˇreruˇsen´ı). Tyto dva reˇzimy mus´ıb´yt pod- porov´any na hardwarov´e´urovni (procesorem). • procesy bˇeˇz´ıobvykle v uˇzivatelsk´em reˇzimu, do reˇzimu j´adra pˇrech´az´ıbud’ instrukc´ı synchronn´ıho pˇreruˇsen´ı (trap) pro vol´an´ı sluˇzby j´adra, nebo na z´akladˇeasynchronn´ıch pˇreruˇsen´ı(hodiny, I/O). D´ale se v reˇzimu j´adra oˇsetˇru- j´ıv´yjimeˇcn´estavy procesoru (v´ypadek str´anky, naruˇsen´ıochrany pamˇeti, ne- zn´am´ainstrukce apod.). Nˇekter´especi´aln´ıakce jsou zajiˇst’ov´any syst´emov´ymi procesy, kter´ebˇeˇz´ıcelou dobu v reˇzimu j´adra. • klasick´eUNIXov´ej´adro je tvoˇreno monolitick´ym k´odem. P˚uvodnˇebylo po- tˇreba vygenerovat (tj. pˇreloˇzit ze zdrojov´ych text˚ua slinkovat) j´adro pˇri zmˇenˇenˇekter´eho parametru nebo pˇrid´an´ıovladaˇce zaˇr´ızen´ı. V novˇejˇs´ıch im- plementac´ıch je moˇzno nastavovat parametry j´adra, nˇekdy i za bˇehu, pomoc´ı syst´emov´ych utilit bez nutnosti rekompilace j´adra. Modern´ıUNIXy umoˇzˇnuj´ı rozˇsiˇrovat k´od j´adra za bˇehu pomoc´ıtzv. modul˚uj´adra (loadable kernel mo- dules). Napˇr´ıklad syst´em FreeBSD 5.4-RELEASE m´a392 takov´ych modul˚u. • existuj´ıdva zp˚usoby pr´ace s perif´eriemi: blokov´a(block devices) a znakov´a zaˇr´ızen´ı(character, raw devices). Data z blokov´ych zaˇr´ızen´ı(napˇr. disky) proch´azej´ı pˇres vyrovn´avac´ı pamˇeti (buffers) po bloc´ıch, znakov´azaˇr´ızen´ı (napˇr. termin´aly) umoˇzˇnuj´ıpracovat s jednotliv´ymi bajty a nepouˇz´ıvaj´ıvy- rovn´avac´ıpamˇet’.
49 • j´adro nen´ısamostatn´yproces, ale je ˇc´ast´ıkaˇzd´eho uˇzivatelsk´eho procesu. Kdyˇzj´adro nˇeco vykon´av´a, tak vlastnˇeproces, bˇeˇz´ıc´ıv reˇzimu j´adra, nˇeco prov´ad´ı.
Procesy, vl´akna, programy • proces je syst´emov´yobjekt charakterizovan´ysv´ym kontextem, identifikovan´yjednoznaˇcn´ym ˇc´ıslem (process ID, PID); jin´ymi slovy ,,k´od a data v pamˇeti” • vl´akno (thread) je syst´emov´yobjekt, kter´yexistuje uvnitˇr procesu a je charakterizov´an sv´ym stavem. Vˇsechna vl´akna jednoho procesu sd´ıl´ıstejn´ypamˇet’ov´yprostor kromˇeregistr˚u procesoru a z´asobn´ıku; ,,linie v´ypoˇctu”, ,,to, co bˇeˇz´ı” • program ... soubor pˇresnˇedefinovan´eho form´atu obsahuj´ıc´ı instrukce, data a sluˇzebn´ıinformace nutn´eke spuˇstˇen´ı; ,,spustiteln´ysoubor na disku” ◦ pamˇet’ se pˇridˇeluje proces˚um. ◦ procesory se pˇridˇeluj´ı vl´akn˚um. ◦ vl´akna jednoho procesu mohou bˇeˇzet na r˚uzn´ych procesorech.
• kontext je pamˇet’ov´yprostor procesu, obsah registr˚ua datov´estruktury j´adra t´ykaj´ıc´ıse dan´eho procesu • jinak ˇreˇceno – kontext procesu je jeho stav. Kdyˇzsyst´em vykon´av´aproces, ˇr´ık´ase, ˇze bˇeˇz´ıv kontextu procesu. J´adro (klasick´e) obsluhuje pˇreruˇsen´ıv kontextu pˇreruˇsen´eho procesu. • vl´akna se dostala do UNIXu aˇzpozdˇeji, p˚uvodnˇev nˇem existovaly pouze procesy (s jedin´ym hlavn´ım vl´aknem). Moˇznost pouˇz´ıt v procesu v´ıce vl´aken byla zavedena, protoˇze se uk´azalo, ˇze je vhodn´em´ıt v´ıce paraleln´ıch lini´ı v´ypoˇctu nad sd´ılen´ymi daty. • pamˇet’ov´eprostory proces˚ujsou navz´ajem izolovan´e, ale procesy spolu mohou komunikovat (pozdˇeji se dozv´ıme, ˇze mohou i ˇc´asteˇcnˇe sd´ılet pamˇet’).
• procesy jsou entity na ´urovni j´adra, vl´akna mohou b´yt ˇc´asteˇcnˇenebo zcela implementov´ana knihovn´ımi funkcemi (tj. vl´akna nemus´ı j´adro v˚ubec pod- porovat). S vl´akny je spojena menˇs´ıreˇzie neˇzs procesy. • syst´emov´yproces, kter´ybˇeˇz´ına pozad´ıobvykle po celou dobu bˇehu syst´emu a zajiˇst’uje nˇekter´esyst´emov´esluˇzby (inetd, cron, sendmail.. . ) se naz´yv´a d´emon (angl. daemon). Syst´em BSD tedy nem´ave znaku ˇcerta, ale d´emona.
50 J´adro, reˇzimy, pˇreruˇsen´ı(klasick´yUNIX)
• procesy typicky bˇeˇz´ıv uˇzivatelsk´em reˇzimu • syst´emov´evol´an´ızp˚usob´ıpˇrepnut´ıdo reˇzimu j´adra • proces m´apro kaˇzd´yreˇzim samostatn´yz´asobn´ık • j´adro je ˇc´ast´ıkaˇzd´eho uˇzivatelsk´eho procesu, nen´ıto samostn´y proces (procesy) • pˇrepnut´ına jin´yproces se naz´yv´a pˇrepnut´ıkontextu • obsluha pˇreruˇsen´ıse prov´ad´ıv kontextu pˇreruˇsen´eho procesu • klasick´ej´adro je nepreemptivn´ı
• j´adro nen´ıoddˇelen´amnoˇzina proces˚u, bˇeˇz´ıc´ıch paralelnˇes uˇzivatelsk´ymi procesy, ale je ˇc´ast´ıkaˇzd´eho uˇzivatelsk´eho procesu.
• pˇrechod mezi uˇzivatelsk´ym reˇzimem a reˇzimem j´adra nen´ıpˇrepnut´ıkontextu – proces bˇeˇz´ıpoˇr´ad v tom sam´em • pˇreruˇsen´yproces nemusel pˇreruˇsen´ıv˚ubec zp˚usobit • v reˇzimu j´adra m˚uˇze proces pˇristupovat i k adres´am j´adra, kter´az uˇzivatelsk´e- ho reˇzimu pˇr´ıstupn´anejsou; takt´eˇzm˚uˇze pˇristupovat k instrukc´ım (napˇr. in- strukce manipuluj´ıc´ıse stavov´ym registrem), jejichˇz vykon´an´ıv uˇzivatelsk´em reˇzimu vede k chybˇe
• pˇreruˇsovac´ırutina se nem˚uˇze zablokovat, protoˇze t´ım by zablokovala proces; proces se totiˇzm˚uˇze zablokovat jen ze sv´evlastn´ıv˚ule. Modern´ıUnixy dnes pouˇz´ıvaj´ıinterrupt vl´akna, v jejichˇzkontextu se mohou drivery zablokovat. • to, ˇze klasick´eunixov´ej´adro je nepreemptivn´ıznamen´a, ˇze jeden proces nem˚uˇze zablokovat jin´yproces
• pˇri obsluze pˇreruˇsen´ıse m˚uˇze st´at, ˇze nastane dalˇs´ıpˇreruˇsen´ı. Pokud je jeho priorita vˇetˇs´ı, je procesorem pˇrijmuto. Posloupnost pˇrijmut´ych pˇreruˇsen´ıje uchov´ana v z´asobn´ıku kontextov´ych vrstev.
• u modern´ıch kernel˚uje situace ˇcasto velmi rozd´ıln´a– obsluha pˇre- ruˇsen´ı, preeptivnost kernelu atd.; k nˇekter´ym vˇecem se moˇzn´ado- staneme pozdˇeji bˇehem semestru
51 Vol´an´ısluˇzeb a komunikace mezi procesy
• UNIX proces proces proces rozhran´ıvol´an´ıj´adra j´adro
• distribuovan´yOS
uˇzivatelsk´y uˇzivatelsk´y proces proces server server server j´adro j´adro j´adro j´adro j´adro
• pokud unixov´yproces vyˇzaduje proveden´ısyst´emov´esluˇzby, pomoc´ısyst´e- mov´eho vol´an´ıpˇred´aˇr´ızen´ıj´adru. J´adro je kus k´odu sd´ılen´yvˇsemi procesy (ovˇsem pˇr´ıstupn´yjen pro ty, kter´ejsou pr´avˇev reˇzimu j´adra). J´adro tedy nen´ısamostatn´yprivilegovan´yproces, ale vˇzdy bˇeˇz´ı v r´amci nˇekter´eho pro- cesu (toho, kter´ypoˇz´adal j´adro o sluˇzbu, nebo toho, kter´ybˇeˇzel v okamˇziku pˇr´ıchodu pˇreruˇsen´ı). • komunikace mezi procesy v UNIXu je ˇreˇsena pomoc´ısyst´emov´ych vol´an´ı, je tedy zprostˇredkovan´aj´adrem. • aby to nebylo tak jednoduch´e, mohou existovat syst´emov´e procesy (oznaˇco- van´ejako kernel threads), kter´ebˇeˇz´ıcelou dobu v reˇzimu j´adra. Naprost´a vˇetˇsina syst´emov´ych proces˚uvˇsak bˇeˇz´ıv uˇzivatelsk´em reˇzimu a liˇs´ıse jen t´ım, ˇze maj´ıvˇetˇs´ıpˇr´ıstupov´apr´ava. Pl´anovaˇc proces˚upˇrep´ın´amezi procesy a t´ım umoˇzˇnuje bˇeh v´ıce proces˚usouˇcasnˇei na jednom procesoru. Na multi- procesorov´ych poˇc´ıtaˇc´ıch pak funguje skuteˇcn´yparalelismus proces˚ua vl´aken (dokonce se proces m˚uˇze pˇri pˇrepl´anov´an´ıdostat i na jin´yprocesor). • v distribuovan´em operaˇcn´ım syst´emu m´aj´adro obvykle formu mikroj´adra, tj. zajiˇst’uje pouze nejz´akladnˇejˇs´ısluˇzby ˇr´ızen´ıprocesoru, pˇridˇelov´an´ıpamˇeti a komunikace mezi procesy. Vyˇsˇs´ı syst´emov´esluˇzby, kter´ejsou v UNIXu souˇc´ast´ıj´adra (napˇr. pˇr´ıstup k syst´emu soubor˚u) jsou realizov´any speci´aln´ımi procesy (servery) bˇeˇz´ıc´ımi v uˇzivatelsk´em reˇzimu procesoru. J´adro pˇred´a poˇzadavek uˇzivatelsk´eho procesu pˇr´ısluˇsn´emu serveru, kter´ym˚uˇze bˇeˇzet i na jin´em uzlu s´ıtˇe. • dostupn´ych mikrokernel˚uje v dneˇsn´ıdobˇemnoho. M˚uˇzete zkusit napˇr´ıklad Minix (unix-like v´yukov´ysyst´em), pˇr´ıpadnˇesyst´em HURD, kter´ybˇeˇz´ınad mikroj´adrem Mach.
52 Syst´emov´avol´an´ı, funkce • v UNIXu se rozliˇsuj´ı syst´emov´avol´an´ı a knihovn´ıfunkce. Toto rozliˇsen´ıdodrˇzuj´ıi manu´alov´estr´anky: sekce 2 obsahuje syst´emov´avol´an´ı(syscalls), sekce 3 knihovn´ıfunkce (library functions). – knihovn´ıfunkce se vykon´avaj´ıv uˇzivatelsk´em reˇzimu, stejnˇe jako ostatn´ık´od programu. – syst´emov´avol´an´ımaj´ıtak´etvar vol´an´ıfunkce. Pˇr´ısluˇsn´a funkce ale pouze dohodnut´ym zp˚usobem zpracuje argumenty vol´an´ıa pˇred´aˇr´ızen´ıj´adru pomoc´ıinstrukce synchronn´ıho pˇreruˇsen´ı. Po n´avratu z j´adra funkce uprav´ıv´ysledek a pˇred´a ho volaj´ıc´ımu. • standardy tyto dvˇekategorie nerozliˇsuj´ı, protoˇze z hlediska program´atora je jedno, jestli urˇcitou funkci provede j´adro nebo knihovna.
• zjednoduˇsenˇelze ˇr´ıci, ˇze syst´emov´evol´an´ıje funkce, kter´ajen uprav´ısv´ear- gumenty do vhodn´epodoby, pˇrepne reˇzim procesoru a skuteˇcnou pr´aci nech´a na j´adru. Nakonec zase uprav´ıv´ysledek. Knihovn´ıfunkce m˚uˇze a nemus´ıvolat j´adro, ale vˇzdy sama dˇel´anˇejakou netrivi´aln´ıˇcinnost v uˇzivatelsk´em reˇzimu. • v assembleru je moˇzn´ezavolat vol´an´ıj´adra pˇr´ımo • API j´adra je definovan´ena ´urovni vol´an´ıfunkc´ıstandardn´ıknihovny, nikoliv na ´urovni pˇreruˇsen´ıa datov´ych struktur pouˇz´ıvan´ych tˇemito funkcemi pro pˇred´an´ıˇr´ızen´ıj´adru. Mechanismus pˇrepnut´ı mezi uˇzivatelsk´ym reˇzimem a reˇzimem j´adra se totiˇzm˚uˇze liˇsit nejen v z´avislosti na hardwarov´eplatformˇe, ale i mezi r˚uzn´ymi verzemi syst´emu na stejn´em hardwaru.
53 N´avratov´ehodnoty syst´emov´ych vol´an´ı • celoˇc´ıseln´an´avratov´ahodnota (int, pid t, off t, apod.) – >= 0 . . . operace ´uspˇeˇsnˇeprovedena – == -1 . . . chyba • n´avratov´ahodnota typu ukazatel – != NULL . . . operace ´uspˇeˇsnˇeprovedena – == NULL . . . chyba • po ne´uspˇeˇsn´em syst´emov´em vol´an´ıje k´od chyby v glob´aln´ı promˇenn´e extern int errno; • ´uspˇeˇsn´evol´an´ınemˇen´ıhodnotu v errno! Je tedy tˇreba nejprve otestovat n´avratovou hodnotu a pak teprve errno. • chybov´ehl´aˇsen´ıpodle hodnoty v errno vyp´ıˇse funkce void perror(const char *s ); • textov´ypopis chyby s dan´ym ˇc´ıslem vr´at´ıfunkce char *strerror(int errnum );
• funkce pro pr´aci s vl´akny pthread *() nenastavuj´ı errno, ale vrac´ıbud’ nulu (´uspˇech) nebo pˇr´ımo k´od chyby. • pro nˇekter´avol´an´ım˚uˇze m´ıt smysl i n´avratov´ahodnota -1. Pak je tˇreba nejprve nastavit errno = 0 a po n´avratu zkontrolovat, zda se errno zmˇenilo. Napˇr. funkce strtol() vrac´ıpˇri chybˇe0, coˇzje platn´ahodnota i pro spr´avn´y v´ysledek (a −1 je samozˇrejmˇeplatn´yv´ysledek tak´e). • je tedy vˇzdy nutn´esi pˇreˇc´ıst manu´alovou str´anku pro pˇr´ıˇsluˇsn´evol´an´ınebo knihovn´ıfunkci • pozn.: ´uspˇeˇsnost funkc´ıze stdio.h je tˇreba testovat pomoc´ı int ferror(FILE*stream );, protoˇze jinak nelze rozliˇsit mezi chybou a kon- cem streamu. Vzhledem k tomu, ˇze tyto funkce nepouˇz´ıv´ame (kromˇe printf/fprintf na stdout/stderr), nemˇeli byste ji potˇrebovat.
54 Obsah
• ´uvod, v´yvoj UNIXu a C, program´atorsk´en´astroje • z´akladn´ıpojmy a konvence UNIXu a jeho API • pˇr´ıstupov´apr´ava, perifern´ızaˇr´ızen´ı, syst´em soubor˚u • manipulace s procesy, spouˇstˇen´ıprogram˚u • sign´aly • synchronizace a komunikace proces˚u • s´ıt’ov´akomunikace • vl´akna, synchronizace vl´aken • ??? - bude definov´ano pozdˇeji, podle toho kolik zbyde ˇcasu
Uˇzivatel´ea skupiny
beran:x:1205:106:Martin Beran:/home/beran:/bin/bash v´yznam jednotliv´ych pol´ı: uˇzivatelsk´ejm´eno, zak´odovan´eheslo (novˇev /etc/shadow), ˇc´ıslo uˇzivatele (UID); superuˇzivatel (root) m´a UID 0, ˇc´ıslo prim´arn´ıskupiny (GID), pln´ejm´eno, domovsk´yadres´aˇr, login-shell
sisal:*:106:forst,beran v´yznam jednotliv´ych pol´ı: jm´eno skupiny, heslo pro pˇrepnut´ıdo skupiny, ˇc´ıslo skupiny (GID), seznam ˇclen˚uskupiny
55 • informace o uˇzivatel´ıch v souborech /etc/passwd,a /etc/group jsou zpra- cov´av´any r˚uzn´ymi syst´emov´ymi programy, napˇr. login (pˇrihl´aˇsen´ıdo syst´e- mu na z´akladˇeuˇzivatelsk´eho jm´ena a hesla) nebo su (zmˇena identity). J´adro o tˇechto souborech nic nev´ı, pouˇz´ıv´apouze numerickou identifikaci uˇzivatele a skupiny.
• dnes jiˇzhesla nejsou z bezpeˇcnostn´ıch d˚uvod˚upˇr´ımo v /etc/passwd, ale napˇr´ıklad v /etc/shadow, kter´ybˇeˇzn´emu uˇzivateli pˇr´ıstupn´ynen´ı. A napˇr. na FreeBSD se soubor /etc/passwd generuje ze souboru /etc/master.passwd, kter´yzak´odovan´ahesla obsahuje.
• existuj´ı i jin´esyst´emy, kter´e(nejen) pro autentizaci /etc/passwd nemus´ı v˚ubec pouˇz´ıvat, napˇr´ıklad NIS (Network Information Service). • skupina uˇzivatele uveden´av /etc/passwd je prim´arn´ı. Tuto skupinovou iden- tifikaci dostanou napˇr. soubory vytvoˇren´eprocesy uˇzivatele. Dalˇs´ıskupiny, ve kter´ych je uˇzivatel uveden v souboru /etc/group, jsou doplˇnkov´e(supple- mentary) a rozˇsiˇruj´ıpˇr´ıstupov´apr´ava uˇzivatele: skupinov´ypˇr´ıstup je povolen ke vˇsem objekt˚um, jejichˇzskupinov´yvlastn´ık je roven bud’ prim´arn´ı, nebo jedn´ez doplˇnkov´ych skupin. • p˚uvodnˇemˇel v UNIXu kaˇzd´yuˇzivatel vˇzdy aktivn´ıpouze jednu skupinovou identitu. Po nalogov´an´ıbyl ve sv´eprim´arn´ıskupinˇe, pro z´ısk´an´ıpr´av jin´e skupiny bylo tˇreba se do n´ıpˇrepnout pˇr´ıkazem newgrp (skupinov´aobdoba su, ˇr´ıd´ıse obsahem souboru /etc/group), kter´yspustil nov´yshell. • v novˇejˇs´ıch UNIXech nen´ıtˇreba pro pˇr´ıstup k soubor˚um mˇenit prim´arn´ısku- pinovou identitu procesu, pokud uˇzivatel patˇr´ıdo potˇrebn´eskupiny. Zmˇena identity je nutn´a, pouze kdyˇzchceme vytv´aˇret soubory s jinou skupinovou identitou neˇzje prim´arn´ıskupina uˇzivatele. Lok´alnˇe pro urˇcit´yadres´aˇrtoho lze dos´ahnout nastaven´ım skupinov´eho vlastn´ıka adres´aˇre na poˇzadovanou skupinu a nastaven´ım bitu SGID v pˇr´ıstupov´ych pr´avech adres´aˇre – to plat´ı pro syst´emy zaloˇzen´ena System V. U BSD staˇc´ızmˇenit poˇzadovanou skupinu u adres´aˇre. • druh´apoloˇzka v ˇr´adc´ıch /etc/group obsahuje zak´odovan´eskupinov´eheslo pouˇz´ıvan´epˇr´ıkazem newgrp, to se jiˇzdnes nepouˇz´ıv´a. Napˇr´ıklad na FreeBSD je pˇr´ıkaz newgrp pˇr´ıstupn´yuˇzjen superuˇzivateli (kv˚uli vol´an´ı setgroups).
56 Name service switch
• dneˇsn´ısyst´emy nejsou omezeny na pouˇz´ıv´an´ı /etc/passwd a /etc/groups • syst´em pouˇz´ıv´a datab´aze (passwd, groups, protocols, ...) • data datab´az´ıpoch´azej´ıze zdroj˚u (soubory, DNS, NIS, LDAP, ...) • soubor nsswitch.conf definuje jak´edatab´aze pouˇz´ıvaj´ıjak´e zdroje • knihovn´ıfunkce toto samozˇrejmˇemus´ıexplicitnˇepodporovat • je moˇzn´enˇekter´ezdroje kombinovat, napˇr´ıklad uˇzivatel se nejdˇr´ıve m˚uˇze hledat v /etc/passwd a pot´ev NISu • poprv´ese objevilo v Solarisu, pot´epˇrevzato dalˇs´ımi syst´emy
• syst´emy maj´ıtypicky manu´alovou str´anku nsswitch.conf(5), kde lze nal´ezt podrobnosti v z´avislosti na konkr´etn´ım operaˇcn´ım syst´emu • zde je ˇc´ast skuteˇcn´eho souboru nsswitch.conf ze stroje u-us:
passwd: files ldap group: files ldap
# You must also set up the /etc/resolv.conf file for DNS name # server lookup. See resolv.conf(4). hosts: files dns
# Note that IPv4 addresses are searched for in all of the # ipnodes databases before searching the hosts databases. ipnodes: files dns
networks: files protocols: files rpc: files ethers: files
57 Testov´an´ıpˇr´ıstupov´ych pr´av • uˇzivatel je identifikov´an ˇc´ıslem uˇzivatele (UID) a ˇc´ısly skupin, do kter´ych patˇr´ı(primary GID, supplementary GIDs). • tuto identifikaci dˇed´ıkaˇzd´yproces dan´eho uˇzivatele.
• soubor S m´avlastn´ıka (UIDS) a skupinov´eho vlastn´ıka (GIDS). • algoritmus testov´an´ıpˇr´ıstupov´ych pr´av pro proces P (UIDP ,GIDP ,SUPG) a soubor S(UIDS,GIDS): Jestliˇze pak P roces m´av˚uˇci Souboru
if(UIDP == 0) . . . vˇsechna pr´ava
else if(UIDP == UIDS) . . . pr´ava vlastn´ıka
else if(GIDP == GIDS ||
GIDS ∈ SUPG) . . . pr´ava ˇclena skupiny else . . . pr´ava ostatn´ıch
• procesy superuˇzivatele root mohou mˇenit svoji uˇzivatelskou a skupinovou identitu. Toho vyuˇz´ıv´anapˇr. proces login, kter´ybˇeˇz´ıjako root a po zkon- trolov´an´ıjm´ena a hesla spust´ıshell s uˇzivatelskou identitou (pomoc´ıvol´an´ı setuid() – viz dalˇs´ıslajdy). • z algoritmu plyne, ˇze pro roota nen´ı relevantn´ı nastaven´ıpr´av (m´avˇzdy neomezen´ypˇr´ıstup). Pokud se shoduje uˇzivatel, nepouˇzij´ı se nikdy pr´ava skupiny nebo ostatn´ıch, i kdyˇzpovoluj´ıv´ıce neˇzuˇzivatelsk´apr´ava. Podobnˇe pr´ava ostatn´ıch se nepouˇzij´ı, jestliˇze se shoduje skupinov´aidentita. Tedy pokud m´am˚uj soubor nastaveny pr´ava ---rwxrwx, nemohu ho ˇc´ıst, zapisovat ani spustit (dokud nastaven´ıpr´av nezmˇen´ım). • nˇekter´esyst´emy se odkl´anˇej´ıod klasick´eho modelu, kdy mnoho proces˚ubˇeˇzelo pod uˇzivatelem s UID 0 a pˇri bezpeˇcnostn´ı chybˇev takov´e aplikaci ˇcasto ´utoˇcn´ık z´ıskal vl´adu nad cel´ym syst´emem a zav´adˇej´ımodely jako je least privilege model v Solarisu 10, systrace v OpenBSD, . . .
58 Re´aln´ea efektivn´ıUID/GID • u kaˇzd´eho procesu se rozliˇsuje: – re´aln´eUID (RUID) – kdo je skuteˇcn´ym vlastn´ıkem procesu – efektivn´ıUID (EUID) – uˇzivatel, jehoˇzpr´ava proces pouˇz´ıv´a – uschovan´eUID (saved SUID) – p˚uvodn´ıefektivn´ıUID • podobnˇese rozliˇsuje re´aln´e, efektivn´ıa uschovan´eGID procesu. • obvykle plat´ı RUID==EUID && RGID==EGID. • prop˚ujˇcov´an´ıpr´av . . . spuˇstˇen´ıprogramu s nastaven´ym SUID (set user ID) bitem zmˇen´ıEUID procesu na UID vlastn´ıka programu, RUID se nezmˇen´ı. • podobnˇeSGID bit ovlivˇnuje EGID procesu. • pˇri kontrole pˇr´ıstupov´ych pr´av se pouˇz´ıvaj´ıvˇzdy EUID, EGID a supplementary GIDs.
• bity SUID a SGID se pouˇz´ıvaj´ıu program˚u, kter´epotˇrebuj´ıvˇetˇs´ıpˇr´ıstupov´a pr´ava, neˇzm´auˇzivatel, jenˇzje spouˇst´ı. Pˇr´ıkladem je program passwd, kter´y mus´ıaktualizovat soubory /etc/passwd a /etc/shadow, kde ten prvn´ıne- m˚uˇze bˇeˇzn´yuˇzivatel mˇenit a druh´yz nich ani ˇc´ıst. Dalˇs´ıpˇr´ıklad je program su. Ten mus´ım´ıt pr´avo libovolnˇezmˇenit uˇzivatelskou a skupinovou identitu, coˇzje privilegium proces˚us UID 0. • SUID a SGID programy by mˇely b´yt peˇclivˇenaprogramov´any, aby dovolily pouze ty operace, pro kter´ejsou urˇceny, a neumoˇznily zneuˇz´ıt jejich privilegia pro neopr´avnˇen´eakce (napˇr. spuˇstˇen´ırootovsk´eho shellu). Zkuˇsenost ukazuje, ˇze tyto programy jsou jednou z nejˇcastˇejˇs´ıch pˇr´ıˇcin bezpeˇcnost´ıch probl´em˚u UNIXov´ych syst´em˚u. • z´akladn´ım pravidlem pro SUID programy je: nepiˇste je pokud to nen´ı opravdu nezbytn´e. Je to typick´em´ısto pro generov´an´ıbezpeˇcnostn´ıch chyb protoˇze dobˇre (= bezpeˇcnˇe) napsat sloˇzitˇejˇs´ıSUID program nen´ıjednoduch´e. • toto jsou pravidla pro zmˇeny: – beˇzn´yuˇzivatel nem˚uˇze zmˇenit sv´eRUID nebo uschovan´eSUID (vyj´ımka je pˇri vol´an´ı exec(), viz strana 113) – proces m˚uˇze vˇzdy zmˇenit sv´eEUID na to z RUID nebo z uschovan´eho UID. Toto zaruˇcuje, ˇze v SUID programu je moˇzn´elibovolnˇemˇenit EUID mezi t´ım p˚uvodn´ım kter´ym proces z´ıskal pr´ava vlastn´ıka a mezi UID skuteˇcn´eho uˇzivatele kter´ydan´yproces spustil) – root m˚uˇze vˇsechno, a kdyˇzzmˇen´ıRUID, tak se z´aroveˇn zmˇen´ıi uchovan´e UID – nemˇelo by smysl mˇenit jen jedno z nich kdyˇzkter´ekoli m˚uˇzete pouˇz´ıt pro nastaven´ıEUID.
59 Identifikace vlastn´ıka procesu
• uid t getuid(void) vrac´ıre´aln´euser ID volaj´ıc´ıho procesu. • uid t geteuid(void) vrac´ıefektivn´ıuser ID volaj´ıc´ıho procesu. • gid t getgid(void) vrac´ıre´aln´egroup ID volaj´ıc´ıho procesu. • gid t getegid(void) vrac´ıefektivn´ıgroup ID volaj´ıc´ıho procesu. • int getgroups(int gidsz, gid t glist []) – do glist d´anejv´yˇse gidsz supplementary group IDs volaj´ıc´ıho procesu a vr´at´ıpoˇcet vˇsech GIDs procesu.
• getgroups(): kdyˇz gidsz == 0, jen vr´at´ıpoˇcet skupin. Kdyˇz 0 < gidsz < #skupin, vr´at´ı -1. • v UNIXu je mnoho typ˚ujako uid_t, gid_t, size_t, apod. Vesmˇes jsou to celoˇc´ıseln´etypy, ˇcasto je najdete v /usr//sys/types.h
60 Zmˇena vlastn´ıka procesu
• int setuid(uid t uid ); – v procesu s EUID == 0 nastav´ıRUID, EUID i saved-SUID na uid (viz tak´epozn´amky na stranˇe59). – pro ostatn´ıprocesy nastavuje jen EUID, a uid mus´ıb´yt bud’ rovn´eRUID nebo uschovan´emu SUID • int setgid(gid t gid ); obdoba setuid(), nastavuje group-IDs procesu. • int setgroups(int ngroups, gid t *gidset ) nastavuje supplementary GIDs procesu, m˚uˇze b´yt pouˇzito jen superuˇzivatelsk´ym procesem.
• co v´yˇse uveden´etedy znamen´a: proces s efektivn´ımi pr´avy superuˇzivatele m˚uˇze libovolnˇemˇenit identitu. Ostatn´ıprocesory mohou pouze stˇr´ıdat sv´a re´aln´aa efektivn´ıpr´ava.
• program login vyuˇz´ıv´avol´an´ı setuid() • pokud chce process s UID == 0 zmˇenit svou identitu, mus´ınejprve volat setgid() a setgroups(). Teprve pak lze zavolat setuid(). Pˇri opaˇcn´em poˇrad´ıvol´an´ıby proces po proveden´ı setuid uˇznemˇel pr´ava na setgid() a setgroups(). • setgroups() nen´ıuvedeno v UNIX 98 ani UNIX 03.
• RUID/EUID jsou uloˇzen´ev z´aznamu tabulky proces˚upro pˇr´ısluˇsn´yproces a z´aroveˇnv tzv. u-area (viz napˇr´ıklad [Bach]). EUID v tabulce proces˚use naz´yv´ajiˇzzm´ınˇen´euschovan´eUID, neboli saved UID. Jak jiˇzbylo ˇreˇceno, uschovan´eUID se pouˇz´ıv´apro kontrolu, kdyˇzse proces chce vr´atit k EUID, se kter´ym byl spuˇstˇen (po t´e, co doˇcasnˇenastavil sv´e EUID na UID uˇzivatele, kter´yproces spustil, tj. na RUID). • pokud tedy jako root vytvoˇr´ıte SUID program a v nˇem zavol´ate setuid() pro jak´eholi UID mimo 0, jiˇzse v programu k EUID==0 nem˚uˇzete vr´atit. V tom pˇr´ıpadˇebyste museli pouˇz´ıt vol´an´ı seteuid(), kter´enastavuje pouze EUID.
61 Syst´em soubor˚u
• adres´aˇre tvoˇr´ıstrom, spolu se soubory acyklick´ygraf (na jeden soubor m˚uˇze existovat v´ıce odkaz˚u). • kaˇzd´yadres´aˇrnav´ıc obsahuje odkaz na sebe ’.’ (teˇcka) a na nadˇrazen´yadres´aˇr’..’ (dvˇeteˇcky). • pomoc´ırozhran´ısyst´emu soubor˚use pˇristupuje i k dalˇs´ım entit´am v syst´emu: – perifern´ızaˇr´ızen´ı – pojmenovan´eroury – sokety – procesy (/proc) – pamˇet’ (/dev/mem, /dev/kmem) – pseudosoubory (/dev/tty, /dev/fd/0,...) • z pohledu j´adra je kaˇzd´yobyˇcejn´ysoubor pole bajt˚u. • vˇsechny (i s´ıt’ov´e) disky jsou zapojeny do jednoho stromu.
• root m˚uˇze v nˇekter´ych syst´emech strukturu adres´aˇr˚u zacyklit, ale t´ım zmate utility pro proch´azen´ı filesyst´emu; moc se cyklick´estruktury nepouˇz´ıvaj´ı. Symbolick´elinky na adres´aˇre funguj´ıvˇsude.
• pojmenovan´eroury (viz strana 81) lze pouˇz´ıt i mezi procesy, kter´enejsou pˇr´ıbuzensky spˇr´ıznˇen´e. Jinak funguj´ıstejnˇejako nepojmenovan´eroury. • zmiˇnovan´esokety jsou v dom´enˇeUNIX, tj. slouˇz´ıpro komunikaci v r´amci jednoho syst´emu. Sokety z dom´eny INET, pˇres kter´eprob´ıh´as´ıt’ov´akomuni- kace, se v syst´emu soubor˚uneobjevuj´ı. S´ıt’ov´akomunikace zaˇc´ın´ana stranˇe 155. • debuggery pouˇz´ıvaj´ıpamˇet’ov´eobrazy proces˚udostupn´ev /proc. Ve vˇetˇsinˇe unix-like syst´em˚uobsahuje podstrom /proc ´udaje o j´adru syst´emu a bˇeˇz´ıc´ıch procesech ve formˇetextov´ych soubor˚u. • dneˇsn´ımodern´ıunixy m´ıvaj´ıspeci´aln´ıfilesyst´em devfs, jehoˇzobsah odr´aˇz´ı aktu´aln´ıkonfiguraci syst´emu co se t´yˇce pˇripojen´ych zaˇr´ızen´ı. Tj. napˇr. pˇri pˇripojen´ıUSB sticku se v /dev objev´ıpˇr´ısluˇsn´ediskov´ezaˇr´ızen´ı. Po fyzick´em odpojen´ızaˇr´ızen´ıodkaz z adres´aˇrov´estruktury opˇet zmiz´ı.
62 Jednotn´yhierarchick´ysyst´em soubor˚u
/
dev etc usr home tty
• svazek (angl. file system) je ˇc´ast souborov´eho syst´emu, kterou lze samostatnˇe vytvoˇrit, pˇripojit, zruˇsit... Kaˇzd´yfilesyst´em m˚uˇze m´ıt jinou vnitˇrn´ıstrukturu (s5, ufs, ext2, xfs, atd.) a m˚uˇze b´yt uloˇzen na lok´aln´ım disku nebo na jin´em poˇc´ıtaˇci a pˇr´ıstupn´ypo s´ıti (nfs, afs). • po startu j´adra je pˇripojen´yjen koˇrenov´yfilesyst´em, dalˇs´ıfilesyst´emy se za- pojuj´ıdo hierarchie na m´ısta adres´aˇr˚upˇr´ıkazem mount. Tento pˇr´ıkaz je moˇzn´e spustit ruˇcnˇe(uˇzivatel root libovolnˇe, ostatn´ıpouze na nˇekter´ych syst´emech a s omezen´ımi) nebo automaticky bˇehem inicializace syst´emu (ˇr´ıd´ıse obsa- hem souboru /etc/fstab). Pˇred zastaven´ım syst´emu se filesyst´emy odpojuj´ı pˇr´ıkazem umount. • dalˇs´ımoˇznost je pˇripojen´ıfilesyst´emu na ˇz´adost (pˇri prvn´ım pˇr´ıstupu) a jeho odpojen´ıpo urˇcit´edobˇeneˇcinnosti. Tuto funkci zajiˇst’uje d´emon automounter (autofs, automount, amd). • UNIX nem´aˇz´adn´eA, B, C, D. . . disky apod.
63 Typick´askladba adres´aˇr˚u
/bin . . . z´akladn´ısyst´emov´epˇr´ıkazy /dev . . . speci´aln´ısoubory (zaˇr´ızen´ı, devices) /etc . . . konfiguraˇcn´ıadres´aˇr /lib . . . z´akladn´ısyst´emov´eknihovny /tmp . . . veˇrejn´yadres´aˇrpro doˇcasn´esoubory /home . . . koˇren domovsk´ych adres´aˇr˚u /var/adm . . . administrativn´ısoubory (ne na BSD) /usr/ . . . knihovny header˚upro C /usr/local . . . lok´alnˇeinstalovan´ysoftware /usr/man . . . manu´alov´estr´anky /var/spool . . . spool (poˇsta, tisk,...)
• v /bin, /lib, /sbin jsou pˇr´ıkazy a knihovny potˇrebn´epˇri startu syst´emu, kdy je pˇripojen pouze koˇrenov´yfilesyst´em. Ostatn´ıpˇr´ıkazy a knihovny jsou typicky v /usr/bin, /usr/lib a /usr/sbin (/usr b´yv´aˇcasto samostatn´y filesyst´em, ˇc´ımˇzjeho obsah nen´ıdostupn´ybˇehem startu syst´emu). • podstrom /usr obsahuje soubory, kter´ese nemˇen´ı pˇri bˇeˇzn´em provozu a nejsou z´avisl´ena konkr´etn´ım poˇc´ıtaˇci. Proto by mˇel j´ıt sd´ılet read-only. Na sv´estanici doma ho ale samozˇrejmˇebudete m´ıt read-write. • v podstromu /var jsou data, kter´ase za provozu mˇen´ıa jsou specifick´apro kaˇzd´ypoˇc´ıtaˇc. • r˚uzn´esyst´emy (i instalace jednoho syst´emu) se ˇcasto liˇs´ı. • hier(7) na FreeBSD popisuje adres´aˇrovou hierarchii tohoto syst´emu, Solaris m´a filesystem(5).
64 Pˇr´ıstup k perifern´ım zaˇr´ızen´ım
• adres´aˇr /dev obsahuje speci´aln´ısoubory zaˇr´ızen´ı. Proces otevˇre speci´aln´ısoubor syst´emov´ym vol´an´ım open() a d´ale komunikuje se zaˇr´ızen´ım pomoc´ıvol´an´ı read(), write(), ioctl(), apod. • speci´aln´ısoubory se dˇel´ına – znakov´e . . . data se pˇren´aˇs´ıpˇr´ımo mezi procesem a ovladaˇcem zaˇr´ızen´ı, napˇr. s´eriov´eporty – blokov´e . . . data proch´az´ısyst´emovou vyrovn´avac´ıpamˇet´ı(buffer cache) po bloc´ıch pevnˇedan´evelikosti, napˇr. disky
• speci´aln´ısoubor identifikuje zaˇr´ızen´ıdvˇema ˇc´ısly – hlavn´ı(major) ˇc´ıslo . . . ˇc´ıslo ovladaˇce v j´adru – vedlejˇs´ı(minor) ˇc´ıslo . . . ˇc´ıslo v r´amci jednoho ovladaˇce
• vyrovn´avac´ıpamˇeti urychluj´ıperifern´ıoperace. Pˇri ˇcten´ıse data hledaj´ınej- prve v bufferu. Teprve kdyˇznejsou k dispozici, tak se ˇctou z disku. Pˇri pˇr´ıˇst´ım ˇcten´ıstejn´eho bloku jsou data v bufferu. Pˇri z´apisu se data uloˇz´ıdo bufferu. Na disk je syst´em pˇrep´ıˇse pozdˇeji. Lze si vynutit i okamˇzit´yz´apis dat na disk. • disky v UNIXu jsou obvykle pˇr´ıstupn´epˇres znakov´e(pouˇz´ıvan´epˇri mkfs – vy- tvoˇren´ısvazku – a fsck – kontrola konzistence) i blokov´erozhran´ı(pouˇz´ıvan´e pˇri norm´aln´ım provozu syst´emu soubor˚u). Nˇekter´esyst´emy (FreeBSD) ale uˇz v /dev v˚ubec soubory pro blokov´azaˇr´ızen´ınemaj´ı, pouze znakov´a. • dˇr´ıve musel administr´ator syst´emu po zmˇenˇehardwarov´ekonfigurace upravit obsah adres´aˇre /dev skriptem MAKEDEV nebo ruˇcnˇe. Dnes (Linux, IRIX, Free- BSD, Solaris, . . . ) jiˇzspeci´aln´ısoubory dynamicky vznikaj´ıa zanikaj´ıpodle toho, jak j´adro detekuje pˇrid´an´ınebo odebr´an´ıhardwarov´ych komponent (viz devfs na stranˇe62). • okamˇzit´yz´apis na disk lze vynutit pˇres O DIRECT command ve vol´an´ı fcntl()
65 Fyzick´euloˇzen´ısyst´emu soubor˚u
• syst´em soubor˚u (svazek, filesystem) lze vytvoˇrit na: – odd´ılu disku (partition) – ˇc´ast disku, na jednom disku m˚uˇze b´yt v´ıce odd´ıl˚u – logick´em odd´ılu (logical volume) – takto lze spojit v´ıce odd´ıl˚u, kter´emohou b´yt i na nˇekolika disc´ıch, do jednoho svazku.
• dalˇs´ımoˇznosti: striping, mirroring, RAID / /home /usr
disk1 disk2 disk3
• v´yraz syst´em soubor˚use pouˇz´ıv´av nˇekolika v´yznamech: – jeden filesyst´em, tj. to, co vyrob´ıpˇr´ıkaz mkfs – cel´ahierarchie pˇripojen´ych svazk˚uv syst´emu (v´ystup pˇr´ıkazu mount) – zp˚usob organizace svazku (tj. typ fs) a tomu odpov´ıdaj´ıc´ımodul j´adra, kter´ys daty manipuluje (UFS2, Ext3, XFS, ...) • striping je od slova stripe, ne strip; podle toho se tak´evyslovuje. Znamen´a, ˇze za sebou n´asleduj´ıc´ıbloky dat se ukl´adaj´ıparalelnˇena r˚uzn´edisky a t´ım se zvyˇsuje pˇrenosov´arychlost. • mirroring ukl´ad´akopie dat pro pˇr´ıpad hav´arie prim´arn´ıho disku. • paritn´ıdisky: data se ukl´adaj´ına dva disky, na tˇret´ıse ukl´ad´aXOR prvn´ıch dvou, po hav´arii libovoln´eho disku jsou vˇsechna data st´ale ˇciteln´a. • jednotliv´e´urovnˇeRAID (Redundant Array of Inexpensive Disks) zahrnuj´ı striping, mirroring a vyuˇzit´ıparitn´ıch disk˚u. • na terminologii je tˇreba d´at velk´ypozor. Napˇr. to, co se v DOS svˇetˇenaz´yv´a partition, se v BSD naz´yv´a slice. Tam jsou pak partitions definov´any v r´amci jednoho slice a v nich se vytv´aˇrej´ıfilesyst´emy. • pokud v´as to zaj´ım´anebo se s t´ım setk´av´ate v praxi, doporuˇcuji vaˇs´ıpozor- nosti ZFS, coˇzje filesyst´em a manaˇzer logick´ych odd´ıl˚u v jednom. Ze Solarisu se jiˇzdostal do FreeBSD od verze 7.0 a tak´edo Mac OS X Leopard (kter´y byl ofici´alnˇevyd´an v ˇr´ıjnu 2007). M˚uˇzete okamˇzitˇe zapomenout na jednotliv´e disky, co je d˚uleˇzit´eje pouze celkov´adiskov´akapacita v syst´emu.
66 Organizace syst´emu soubor˚u s5
blok ˇc. 0 zav´adˇec´ıblok (boot block) 1 superblok 0 912 2 oblast i-uzl˚u(i-nodes) ...
oblast datov´ych blok˚u
• p˚uvodn´ıUNIXov´ysyst´em soubor˚ustandardnˇepouˇz´ıvan´ydo verze System V Release 3; v BSD se prim´arnˇepouˇz´ıval do verze 4.1 • vlastnosti: – bloky d´elky 512, 1024 nebo 2048 bajt˚u – jedin´y(neduplikovan´y) superblok – datov´yprostor pevnˇerozdˇelen´yna oblast i-uzl˚u a oblast datov´ych blok˚u – pˇri velikosti bloku 1024 bajt˚ubyla teoretick´avelikost filesyst´emu pˇres 16 GB • boot block – pro uloˇzen´ızavadˇeˇce OSu • superblok – z´akladn´ıinformace o svazku: poˇcet blok˚upro i-uzly, poˇcet blok˚u svazku, seznam voln´ych blok˚u(pokraˇcuje ve voln´ych bloc´ıch), seznam voln´ych i-uzl˚u(po vyˇcerp´an´ıse prohled´av´atabulka i-uzl˚u), z´amky pro seznamy vol- n´ych blok˚ua i-uzl˚u, pˇr´ıznak modifikace (pro kontrolu korektn´ıho odpojen´ı svazku), ˇcas posledn´ıaktualizace, informace o zaˇr´ızen´ı • i-uzel – typ souboru, pˇr´ıstupov´apr´ava, vlastn´ık, skupina, ˇcasy posledn´ıho pˇr´ıstupu, modifikace dat a modifikace i-uzlu (ˇcas vytvoˇren´ı souboru nen´ı uloˇzen), poˇcet odkaz˚una soubor, velikost souboru, 10 odkaz˚una datov´ebloky a 3 odkazy na nepˇr´ım´ebloky • maxim´aln´ıvelikost souboru: 2113674 blok˚u, tj. pˇribliˇznˇe1 GB pˇri pouˇzit´ı blok˚uvelikosti 512 B • jm´ena soubor˚u– max. 14 znak˚u(14 + 2 = 16, tedy mocnina dvou a tedy bezprobl´emov´euloˇzn´ıadres´aˇrov´ych poloˇzek do blok˚u)
67 • pˇri pouˇzit´ıtohoto filesyst´emu byla v´ykonnost disk˚uvyuˇzita jen cca na 2% a rychlost ˇcten´ıbyla v ˇr´adu jen nˇekolika des´ıtek kilobajt˚uza sekundu (!!!) • pro srovn´an´ı– MS-DOS 2.0 z roku 1983 podporoval pouze FAT12, poˇc´ıtaj´ıc´ı s maxim´aln´ı velikost´ı filesyst´emu 16 MB. Velikost svazku do 2 GB byla umoˇznˇena aˇzve verzi 4.0 (1988); tato verze z´aroveˇnzavedla diskov´evy- rovn´avac´ıpamˇeti, tedy to, co UNIX m´aod sv´eho vzniku v roce 1970...
Navigace v adres´aˇrov´estruktuˇre
i-nodes /etc/passwd i-node2 i-node37 i-node71
data ..2 37 root:x:0:... .. 2 .. 2
etc 37 passwd 71
• kdyˇzcesta zaˇc´ın´aznakem ’/’, zaˇc´ın´anavigace v koˇrenov´em adres´aˇri, jinak zaˇcne v pracovn´ım adres´aˇri procesu. • koˇrenov´yadres´aˇrm´atypicky ˇc´ıslo 2. 0 je pro oznaˇcen´ıpr´azdn´eho uzlu a 1 byla dˇr´ıve pouˇz´ıvan´apro soubor, do kter´eho se vkl´adaly vadn´ebloky, aby je syst´em uˇzd´ale nepouˇz´ıval. • cesta ve kter´eje v´ıce lom´ıtek za sebou je st´ale platn´a, tj. ///a///b///c je ekvivaletn´ı /a/b/c.
68 Linky
hard link origin´al symbolick´ylink /var /etc /usr password 20 passwd 20 passwd 31 ......
i-nodes 0...... 20 31
root:x:0:... data ../etc/passwd
Hard linky lze vytv´aˇret pouze v r´amci jednoho (logick´eho) filesyst´emu.
hardlink
• odkaz na stejn´yi-uzel • vlastnˇedruh´ejm´eno souboru • nen´ırozd´ıl mezi origin´alem a hardlinkem • lze vytv´aˇret jen v r´amci filesyst´emu • nelze vytv´aˇret pro adres´aˇre symbolick´ylink (symlink, softlink)
• pouze odkaz na skuteˇcnou cestu k souboru jin´eho typu (ls -l ho o- znaˇcuje ’l’), tj. symbolick´ylink je typem odliˇsn´yod bˇeˇzn´eho souboru a jeho data obsahuj´ıobyˇcejn´yˇretˇezec – jm´eno cesty, at’ jiˇzrelativn´ınebo absolutn´ı • odliˇsn´echov´an´ıpro origin´al a link (napˇr. pˇri maz´an´ı) • pozor na relativn´ıa absolutn´ıcesty pˇri pˇresouv´an´ısymbolick´eho linku • m˚uˇze ukazovat i na adres´aˇrnebo na neexistuj´ıc´ısoubor
Nejjednoˇsˇs´ızp˚usob jak si ovˇeˇrit, zda dan´edva linky ukazuj´ına stejn´ysoubor na disku je pouˇz´ıt -i pˇrep´ınaˇcpˇr´ıkazu ls.
$ ls -i /etc/passwd 172789 /etc/passwd
69 Vylepˇsen´ısyst´emu soubor˚u • c´ıl: sn´ıˇzen´ıfragmentace soubor˚u, omezen´ıpohybu hlav disku um´ıstˇen´ım i-uzl˚ua datov´ych blok˚ubl´ıˇzk sobˇe • UFS (Unix File System), p˚uvodnˇeBerkeley FFS (Fast File System) • ˇclenˇen´ına skupiny cylindr˚u, kaˇzd´askupina obsahuje – kopii superbloku – ˇr´ıdic´ıblok skupiny – tabulku i-uzl˚u – bitmapy voln´ych i-uzl˚ua datov´ych blok˚u – datov´ebloky • bloky velikosti 4 aˇz8 kB, fragmenty blok˚u • jm´ena dlouh´a255 znak˚u
• superblok v kaˇzd´ecylinder skupinˇeposunut tak, aby superbloky nebyly na stejn´eplotnˇe • dalˇs´ıtypy filesyst´em˚u: UFS2, Ext3, ReiserFS, XFS, ZFS aj. • v http://www.devnull.cz/mff/pvu/common/docs/filesystems.ps je po- rovn´an´ıosmi r˚uzn´ych filesyst´em˚upodle r˚uzn´ych implementaˇcn´ıch krit´eri´ı; nezahrnuje v sobˇeale v´yvoj posledn´ıch let. • UFS byl st´ale 32-bitov´y, coˇzse odr´aˇzelo na maxim´aln´ı d´elce souboru i na maxim´aln´ıvelikosti filesyst´emu • ˇzurn´alov´an´ı(XFS, Ext3, ReiserFS) – snaha o zmenˇsen´ı nebezpeˇc´ıztr´aty dat v pˇr´ıpadˇehav´arie, urychlen´ızotaven´ıpo hav´arii • ZFS – modern´ı128-bitov´yfilesyst´em vyvinut´ySunem, nyn´ıopen-source, v Solarisu 10, ted’ jiˇztak´ev Mac OS X 10.5 a FreeBSD 7.
70 V´yvoj ve spr´avˇeadres´aˇrov´ych poloˇzek
• maxim´aln´ıd´elka jm´ena souboru 14 znak˚unebyla dostaˇcuj´ıc´ı • FFS – d´elka aˇz255; kaˇzd´apoloˇzka z´aroveˇnobsahuje i jej´ıd´elku • nov´efilesyst´emy pouˇz´ıvaj´ıpro vnitˇrn´ıstrukturu adres´aˇr˚ur˚uzn´e varianty B-strom˚u – v´yraznˇezrychluje pr´aci s adres´aˇri obsahuj´ıc´ıvelk´emnoˇzstv´ı soubor˚u – XFS, JFS, ReiserFS, . . . • UFS2 zav´ad´ızpˇetnˇekompatibiln´ıtzv. dirhash pro zrychlen´ı pˇr´ıstupu k adres´aˇr˚um s velk´ym poˇctem soubor˚u
• dirhash pracuje tak, ˇze pˇri prvn´ım pˇreˇcten´ıadres´aˇre se vytvoˇr´ıv pamˇeti hash struktura, n´asledn´epˇr´ıstupy do adres´aˇre jsou pak srovnateln´ese syst´emy pouˇz´ıvaj´ıc´ıB-stromy. T´ımto zp˚usobem je dosaˇzeno zlepˇsen´ıbez toho, aby se mˇenila struktura filesyst´emu na disku. Nelze to ale takto dˇelat do nekoneˇcna, bude zaj´ımav´ejestli FreeBSD v budoucnu pˇrejde na ZFS jako jejich hlavn´ı filesyst´em. • mal´esoubory se ˇcasto ukl´adaj´ıv i-nodech, ˇc´ımˇzse uˇsetˇr´ıdalˇs´ıpˇr´ıstupy na disk
71 Virtu´aln´ısyst´em soubor˚u(Virtual File System)
struct struct struct struct struct file file file file file *file f vnode f vnode f vnode f vnode
VNODE VNODE VNODE VNODE VNODE v data v data v data v data v data INODE INODE INODE INODE INODE s realvp
ufs vnodeops s5 vnodeops spec vnodeops ufs file system s5 file system spec file system
• FFS uveden´yve 4.2BSD byl historicky druh´yunixov´yfilesyst´em. Nˇekteˇr´ı dodavatel´eunixov´ych syst´em˚uho zaˇcali preferovat vzhledem k jeho lepˇs´ımu v´ykonu a nov´ym moˇznostem, jin´yz˚ust´avali d´ale u s5fs z d˚uvodu zpˇetn´ekom- patibility. To d´ale prohlubovalo probl´em jiˇztak nedostateˇcn´einteroperability mezi r˚uzn´ymi unixov´ymi syst´emy. Nˇekter´ym aplikac´ım nav´ıc plnˇenevyho- voval ani jeden z tˇechto filesyst´em˚u. Postupnˇese tak´eobjevovala potˇreba pracovat s ne-unixov´ymi filesyst´emy, napˇr. FAT. A s rostouc´ıpopularitou poˇc´ıtaˇcov´ych s´ıt´ıse zvyˇsovala popt´avka po sd´ılen´ısoubor˚umezi jednotliv´ymi syst´emy, coˇzmˇelo za n´asledek vznik distribuovan´ych filesyst´em˚u– napˇr. NFS (Network File System). • FFS zaveden´ydo syst´emu s VFS se zaˇcal naz´yvat UFS. • vzhledem k v´yˇse popsan´esituaci bylo jen ot´azkou ˇcasu, kdy dojde k funda- ment´aln´ım zmˇen´am v infrastruktuˇre syst´emu soubor˚u, aby souˇcasnˇepodpo- roval v´ıce typ˚ufilesyst´em˚u. Vzniklo nˇekolik r˚uzn´ych implementac´ıod r˚uzn´ych v´yrobc˚u, aˇzse nakonec de facto standardem stala VFS/vnode architektura od firmy Sun Microsystems. V dneˇsn´ıdobˇeprakticky vˇsechny unixov´ea unix- like syst´emy podporuj´ı VFS, i kdyˇzˇcasto se vz´ajemnˇenekompatibiln´ımi ´upravami. VFS se poprv´eobjevilo v roce 1985 v Solarisu 2.0; brzy bylo pˇrevzato BSD – FFS s podporou VFS je pr´avˇeUFS. • hlavn´ı myˇslenka: kaˇzd´emu otevˇren´emu souboru v syst´emu pˇr´ısluˇs´ı struk- tura file (to by vlastnˇebyl jeden slot v n´ami jiˇzzn´am´esyst´emov´eta- bulce otevˇren´ych soubor˚u). Ta ukazuje na vnode (virtual node). Vnode ob- sahuje ˇc´ast nez´avislou na konkr´etn´ım syst´emu soubor˚ua ˇc´ast z´avislou, coˇz m˚uˇze b´yt napˇr´ıklad struktura inode. Ta je specifick´apro kaˇzd´ytyp soubo- rov´eho syst´emu. Kaˇzd´ytyp filesyst´emu implementuje pevnˇedanou
72 sadu funkc´ı pro jednotliv´eoperace nad soubory, na kterou se od- kazuj´ı vˇsechny virtu´aln´ı uzly odpov´ıdaj´ıc´ıdan´emu typu filesyst´emu. Tato sada funkc´ıtedy definuje vnode interface. Kdyˇztedy zavol´ate napˇr´ıklad open(), j´adro zavol´apˇr´ısluˇsnou implementaci v z´avislosti na typu filesyst´emu (napˇr. z modulu ext2fs). Implementaˇcnˇez´avisl´aˇc´ast struktury vnode je pˇr´ıstupn´apouze z funkc´ıpˇr´ısluˇsn´eho typu filesyst´emu; j´adro do n´ıtedy ,,ne- vid´ı” pˇr´ımo. Jak uvid´ıte na dalˇs´ım slajdu, existuje jeˇstˇejedna sada funkc´ı, kter´ase t´yka pr´ace s filesyst´emy jako takov´ymi. Ta pak definuje VFS inter- face. Tyto dvˇesady spoleˇcnˇetvoˇr´ıvnode/VFS rozhran´ı, kter´emu se bˇeˇznˇe ˇr´ık´ajen VFS. • (nebudu zkouˇset) – u speci´aln´ıch soubor˚uje situace sloˇzitˇejˇs´ı, v SVR4 struk- tura file ukazuje na snode (shadow-special-vnode), kter´ydefinuje operace se zaˇr´ızen´ım (pomoc´ısouborov´eho syst´emu spec) a prostˇrednictv´ım ukazatele s realvp se odkazuje na re´aln´yvnode pro operace se speci´aln´ım souborem; ten je potˇreba napˇr´ıklad pro kontrolu pr´av pˇr´ıstupu. Kaˇzd´emu zaˇr´ızen´ım˚uˇze odpov´ıdat v´ıce speci´aln´ıch soubor˚u, a tedy v´ıce snodes a pˇr´ısluˇsn´ych re´aln´ych vnodes. Vˇsechny takov´esnodes pro jedno zaˇr´ızen´ımaj´ı ukazatel s commonvp na jeden spoleˇcn´ysnode (toto nen´ı na obr´azku zachyceno). Pˇri otevˇren´ı speci´aln´ıho souboru se hled´av hash tabulce snodes otevˇren´ych zaˇr´ızen´ıpo- loˇzka odpov´ıdaj´ıc´ıspeci´aln´ımu souboru (podle major a minor ˇc´ısla zaˇr´ızen´ı). Kdyˇzsnode nen´ınalezen, vytvoˇr´ıse nov´y. Tento snode se pak pouˇz´ıv´apˇri operac´ıch se zaˇr´ızen´ım. V´ıce viz napˇr´ıklad [Vahalia].
Hierarchie souborov´ych syst´em˚u
vfs mount list struct file rootvfs f vnode VFS VFS v vfsp VNODE
vfs next vfs next v op INODE vfs data vfs data root vnode root vnode vnodeops super block super block vfs mountedhere vfs op vfs op vfs vnodecovered VNODE mount v vfsp vfsops vfsops v op point INODE in vfssw[] vsw vfsops rootvfs
vnodeops
• struktura vfs obsahuje implementaˇcnˇenez´avisl´einformace o filesyst´emu, nez´avisl´ena konkr´ent´ım typu filesyst´emu (podobnˇejako vnode funguje pro soubory). Tato struktura nereprezentuje konkr´etn´ıtyp filesyst´emu, ale file- syst´em pˇrimontovan´ydo hierarchie soubor˚u. V tomto v´azan´em seznamu tedy m˚uˇze b´yt v´ıce struktur stejn´eho typu souborov´eho syst´emu.
73 • rootvfs – odkaz na root file system • vfsops – tabulka funkc´ıpro konkr´etn´ıtyp syst´emu soubor˚u • vfssw[] – pole odkaz˚una tabulky vfsops pro vˇsechny syst´emem podporo- van´etypy filesyst´em˚u, z tabulky se vyb´ır´apˇri pˇripojov´an´ısvazku podle typu filesyst´emu zadan´eho pˇri vol´an´ı mount() • v vfsp – odkaz z vnode na filesyst´em (strukturu vfs), na kter´em leˇz´ısoubor reprezentovan´ypomoc´ıvnode • v vfsmountedhere – pouze ve vnode, kter´yreprezentuje mount point (ad- res´aˇr, na kter´em je pˇripojen koˇren jin´eho filesyst´emu); odkazuje na strukturu vfs reprezentuj´ıc´ıpˇripojen´yfilesyst´em • v vnodecovered – odkaz na vnode adres´aˇre, na kter´em je filesyst´em pˇripojen
Otevˇren´esoubory z pohledu j´adra I. user file descriptor table file table inode table
: count 1 process A WRONLY @ @ Z Z @ Z @R count 1 Z Z /etc/group Z~ count 2 3 RDONLY Q Q Q process B Qs count 3 : - count 1 /etc/passwd RDWR
• toto je nejjednoduˇsˇs´ıpohled na tabulky v j´adˇre kter´e se t´ykaj´ısoubor˚u, je to pˇrevzato z [Bach]; dnes to je o nˇeco sloˇzitˇejˇs´ı, myˇslenka je ale poˇr´ad stejn´a. Realitˇev´ıce se podobaj´ıc´ıobr´azek je na pˇr´ıˇst´ım slajdu. • kaˇzd´yproces m´asvoji tabulku souborov´ych deskriptor˚u (user file descriptor table) • z t´eto tabulky je odkazovn´ano na syst´emovou tabulku otevˇren´ych soubor˚u syst´emu (file table; ano, tato tabulka je pouze jedna). Zde je m´od otevˇren´ı souboru a tak´e aktu´aln´ıpozice v souboru. • z tabulky otevˇren´ych soubor˚uje odkazov´ano do tabulky naˇcten´ych inod˚uv pamˇeti (dnes jsou to tzv. vnodes – virtual nodes, ale to n´am nyn´ım˚uˇze b´yt ´uplnˇejedno)
74 • tabulka otevˇren´ych soubor˚usyst´emu, kter´avlastnˇevytv´aˇr´ıo jednu ´uroveˇn odkaz˚unav´ıc, je zde proto, aby r˚uzn´eprocesy mohly sd´ılet stejnou aktu´aln´ı pozici v souboru. • pˇri otevˇren´ısouboru pomoc´ıvol´an´ı open() se vˇzdy alokuje nov´yslot v tabulce deskriptor˚ua tak´ev syst´emov´etabulce otevˇren´ych soubor˚u(to je d˚uleˇzit´e!). Sd´ılen´ıse pak v r´amci jednoho procesu dos´ahne duplikac´ıdeskriptor˚u, kdy v´ıce deskriptor˚usd´ıl´ıstejn´yslot v tabulce otevˇren´ych soubor˚usyst´emu nebo v pˇr´ıpadˇer˚uzn´ych proces˚upak pomoc´ı vytvoˇren´ınov´eho procesu pomoc´ı vol´an´ı fork(), viz strana 119.
Otevˇren´esoubory z pohledu j´adra II.
struct proc uf next uf next u first u proc struct struct struct struct user ufchunk ufchunk ufchunk
p cred ...21 0 ... 21 0 ... 21 0 uf ofile[]
f cred struct cred
f next struct struct struct struct struct struct file file file file file file *file f prev f vnode VNODE VNODE VNODE VNODE VNODE
• struktury proc a user vytv´aˇr´ıj´adro pro kaˇzd´yproces a drˇz´ıv nich sluˇzebn´ı informace o procesu. • struktura ufchunk obsahuje NFPCHUNK (obvykle 24) deskriptor˚usoubor˚u, po zaplnˇen´ıse alokuje dalˇs´ı ufchunk. • struktura file (otevˇren´ısouboru) obsahuje m´od souboru (otevˇren pro ˇcten´ı, z´apis, atd.), poˇcet deskriptor˚u, kter´ese na ni odkazuj´ı, ukazatel na vnode a pozici v souboru. Jedno otevˇren´ısouboru m˚uˇze b´yt sd´ıleno v´ıce deskriptory, jestliˇze byl p˚uvodn´ıdeskriptor zkop´ırov´an, napˇr. vol´an´ım fork() nebo dup(). • struktura cred obsahuje uˇzivatelskou a skupinovou identitu procesu, kter´y otevˇrel soubor. • jeden vnode odpov´ıdaj´ıc´ıjednomu souboru m˚uˇze b´yt sd´ılen nˇekolika struk- turami file, pokud byl dan´ysoubor v´ıcekr´at otevˇren. • ne vˇsechny vnodes jsou asociov´any s tabulkou otevˇren´ych soubor˚u. Napˇr. pˇri spuˇstˇen´ıprogramu je potˇreba pˇristupovat do spustiteln´eho souboru a proto se alokuje vnode.
75 Oprava konzistence souborov´eho syst´emu
• pokud nen´ıfilesyst´em pˇred zastaven´ım syst´emu korektnˇe odpojen, mohou b´yt data v nekonzistentn´ım stavu. • ke kontrole a opravˇesvazku slouˇz´ıpˇr´ıkaz fsck. Postupnˇetestuje moˇzn´enekonzistence: – v´ıcen´asobn´eodkazy na stejn´yblok – odkazy na bloky mimo rozsah datov´eoblasti syst´emu soubor˚u – ˇspatn´ypoˇcet odkaz˚una i-uzly – nespr´avn´avelikost soubor˚ua adres´aˇr˚u – neplatn´yform´at i-uzl˚u – bloky kter´enejsou obsazen´eani voln´e – chybn´yobsah adres´aˇr˚u – neplatn´yobsah superbloku • operace fsck je ˇcasovˇen´aroˇcn´a. • ˇzurn´alov´esyst´emy soubor˚u(napˇr. XFS v IRIXu, Ext3 v Linuxu) nepotˇrebuj´ı fsck.
• data se pˇrepisuj´ı na disky z vyrovn´avac´ıch pamˇet´ı se zpoˇzdˇen´ım. Uloˇzen´ı vˇsech vyrovn´avac´ıch pamˇet´ılze vynutit syst´emov´ym vol´an´ım sync(). Perio- dicky vyrovn´avac´ıpamˇeti ukl´ad´azvl´aˇstn´ısyst´emov´yproces (d´emon). • zde je uk´azka fsck na odpojen´y filesyst´em:
toor@shewolf:~# fsck /dev/ad0a ** /dev/ad0a ** Last Mounted on /mnt/flashcard ** Phase 1 - Check Blocks and Sizes ** Phase 2 - Check Pathnames ** Phase 3 - Check Connectivity ** Phase 4 - Check Reference Counts ** Phase 5 - Check Cyl groups 24 files, 8848 used, 12951 free (7 frags, 1618 blocks, 0.0% fragmentation)
76 Dalˇs´ızp˚usoby zajiˇstˇen´ıkonzistence filesyst´emu
• tradiˇcn´ıUFS – synchronn´ız´apis metadat – aplikace vytv´aˇrej´ıc´ınov´ysoubor ˇcek´ana inicializaci inode na disku; tyto operace pracuj´ırychlost´ıdisku a ne rychlost´ıCPU – asynchronn´ız´apis ale ˇcastˇeji zp˚usob´ınekontistenci metadat • ˇreˇsen´ıprobl´em˚us nekonzistenc´ımetadat na disku: – journalling – skupina na sobˇez´avisl´ych operac´ıse nejdˇr´ıve atomicky uloˇz´ıdo ˇzurn´alu; pˇri probl´emech se pak ˇzurn´al m˚uˇze “pˇrehr´at” – bloky metadat se nejdˇr´ıve zap´ıˇs´ıdo non-volatile pamˇeti – soft-updates – sleduje z´avislosti mezi ukazately na diskov´e struktury a zapisuje data na disk metodou write-back tak, ˇze data na disku jsou vˇzdy konzistentn´ı – ZFS je nov´yfilesyst´em v Solarisu, kter´ypouˇz´ıv´a copy-on-write
• filesystem metadata = inodes, directories, free block maps • ext2 dokonce defaultnˇepouˇz´ıv´aasynchronn´ız´apis metadat a je pˇri pouˇz´ıt´ı synchronn´ıho z´apisu v´yraznˇepomalejˇs´ıneˇzUFS • z´avisl´eoperace jsou napˇr´ıklad smaz´an´ı poloˇzky z adres´aˇre a smaz´an´ı dis- kov´eho inode. Pokud by se stalo, ˇze se nejdˇr´ıve smaˇze diskov´yinode a pak te- prve poloˇzka v adres´aˇri, pˇri v´ypadku mezi tˇemito dvˇemi operacemi vnik´ane- konzistence – link ukazuje na diskov´ysoubor, kter´yneexistuje. Nen´ıprobl´em se tomuto vyhnout pˇri synchronn´ım z´apisu metadat (v´ıme kdy a co zapisu- jeme, urˇcujeme tedy poˇrad´ız´apisu), ale pˇri metodˇewrite-back je jiˇznutn´e ˇreˇsit z´avislosti jednotliv´ych blok˚una sebe, protoˇze pˇri klasick´esynchronizaci vyrovn´avac´ıch pamˇet´ına disk j´adro nezaj´ım´a, kter´y blok se zap´ıˇse dˇr´ıv a kter´ypozdˇeji. • ˇcasto jsou bloky na sobˇez´avisl´eve smyˇcce. Soft updates dok´aˇze takovou smyˇcku rozb´ıt t´ım, ˇze provede roll-back a po z´apisu pak roll-forward • v´ykon soft updates je srovnateln´yv´ykonu UFS filesyst´emu s asynchronn´ım z´apisem metadat • teoreticky soft updates zaruˇcuj´ı, ˇze po rebootu nen´ıpotˇreba pouˇz´ıt fsck, tj. ˇze filesyst´em bude v takov´em stavu, ˇze je moˇzn´enabootovat. Je vˇsak nutn´e pouˇz´ıt tzv. background fsck pro opravy nez´avaˇzn´ych chyb – to je povaˇzov´ano st´ale za velkou nev´yhodu soft updates zvl´aˇstˇes t´ım, jak rostou velikosti bˇeˇznˇe pouˇz´ıvan´ych disk˚u. Takovou chybou, kter´anebr´an´ınabootov´an´ı, ale je nutn´e ji odstranit je napˇr´ıklad blok, kter´yje oznaˇcen jako pouˇzit´y, ale ˇz´adn´ysoubor ho nepouˇz´ıv´a.
77 • soft updates nejsou vˇzdy doporuˇcov´any pro root filesyst´em. Probl´em je to, ˇze ztr´ata metadat na root filesyst´emu (viz 30-ti sekundov´aperioda z´apisu) m˚uˇze b´yt v´yraznˇevˇetˇs´ıhrozbou zde neˇzna /usr, /home atd. Dalˇs´ınev´yhodou m˚uˇze b´yt i to, ˇze u soft updates mi smaz´an´ıvelk´eho souboru hned neuvoln´ı m´ısto. • pˇr´ıklad: na bezpeˇcnou operaci rename potˇrebuju pˇri synchronn´ım z´apisu me- tadat 4 z´apisy – zv´yˇsen´ıpoˇctu odkaz˚uv inode, vytvoˇren´ınov´eadres´aˇrov´e poloˇzky, smaz´an´ıstar´e, a opˇetn´esn´ıˇzen´ıpoˇctu odkaz˚uv inode. Kdykoli by syst´em spadnul, nenastane nebezpeˇcn´asituace. Napˇr´ıklad 2 odkazy z ad- res´aˇr˚una inode s referenˇcn´ım poˇctem 1 je probl´em, protoˇze po zruˇsen´ıjed- noho odkazu to bude vypadat, ˇze soubor je st´ale na disku, kdyˇzuˇzbyls jeho data d´avno smaz´ana. Nen´ıteˇzk´esi asi pˇredstavit, co by to mohlo znamenat v pˇr´ıpadˇe, ˇze soubor obsahoval opravdu d˚uleˇzit´adata – napˇr´ıklad z´alohu. Opaˇcn´asituace, tj. jeden odkaz na inode s referenc´ı2 sice tak´enen´ıspr´avn´asi- tuace, ale neohroˇzuje to moˇznost filesyst´em namontovat a norm´alnˇepouˇz´ıvat. V nejhorˇs´ım se stane, ˇze soubor vypad´aˇze jiˇzna disku nen´ıa pˇritom st´ale existuje. U soft updates operace rename vytvoˇr´ıkruˇznici, protoˇze nejdˇr´ıve je potˇreba zapsat zv´yˇsen´ıpoˇctu referenc´ı, pak adres´aˇrov´ebloky a pot´esn´ıˇzen´ı referenc´ı. A protoˇze zv´yˇsen´ı/sn´ıˇzen´ıse t´yk´astejn´eho inode, tak je pˇri z´apisu tˇreba udˇelat roll-back na (ˇreknˇeme) 2, zapsat inode na disk, zapsat bloky adres´ar˚ua pak roll-forward na poˇcet referenc´ı1. Pˇri t´eto akci je nad inodem drˇzen z´amek, takˇze nikdo nenaˇcte starˇs´ıdata. Je jednoduch´euk´azat, ˇze nelze zapsat ˇz´adn´yz tˇech tˇr´ıblok˚uv kruˇznici tak, jak to je na konci operace re- name, ˇze je opravdu nutn´yten roll-back – mohli bychom uvaˇzovat, ˇze inode se vlastnˇenezmˇenil a nen´ıtˇreba ˇreˇsit zda se m˚uˇze/nem˚uˇze zapsat; z´apis nov´eho adres´aˇrov´eho odkazu bez zv´yˇsen´ıpoˇctu odkaz˚uv inodu by n´as totiˇzmohl dostat pˇresnˇedo situace, kter´aje pops´ana o p´ar ˇr´adk˚uv´yˇse.
Pˇr´ıstupov´apr´ava vlastn´ık (u) skupina (g) ostatn´ı(o)
nejvyˇsˇs´ıbit 4 z }| { z }| { z }| { 2 suid 1 sgid r sticky w x • SGID pro soubor bez pr´ava spuˇstˇen´ıpro skupinu v System V: kontrola z´amk˚upˇri kaˇzd´em pˇr´ıstupu (mandatory locking) • sticky bit pro adres´aˇre: pr´avo mazat a pˇrejmenov´avat soubory maj´ıjen vlastn´ıci soubor˚u • SGID pro adres´aˇr: nov´esoubory budou m´ıt stejnou skupinu jako adres´aˇr(System V; u BSD syst´em˚uto funguje jinak, viz pozn´amky)
78 • SGID pro adres´aˇre u BSD syst´em˚uzp˚usob´ı, ˇze soubory a podadres´aˇre vy- tvoˇren´ev tomto adres´aˇri budou m´ıt stejn´eho majitele jako je majitel dan´eho adres´aˇre. Nutn´ym pˇredpokladem je d´ale to, ˇze dan´yUFS filesyst´em mus´ıb´yt namontov´an s suiddir pˇr´ıznakem a v j´adru je option SUIDDIR (a to nen´ı default). Nav´ıc to nefunguje pro roota. Tato moˇznost existuje kv˚uli Sambˇea Nettalku. • sticky bit pro adres´aˇre: pˇrejmenovat nebo smazat soubor m˚uˇze jen jeho vlastn´ık (v nˇekter´ych implementac´ıch staˇc´ıi pr´avo z´apisu do souboru), nesta- ˇc´ıpr´avo z´apisu do adres´aˇre. Toto nastaven´ıse pouˇz´ıv´apro veˇrejn´eadres´aˇre (napˇr. /tmp). • p˚uvodnˇemˇel sticky bit v´yznam i pro spustiteln´esoubory: program s nasta- ven´ym sticky bitem z˚ustal po ukonˇcen´ıv pamˇeti a jeho opˇetovn´espuˇstˇen´ı bylo rychlejˇs´ı. Dnes se sticky bit v tomto v´yznamu uˇznepouˇz´ıv´a. • nˇekter´efilesyst´emy (XFS, AFS, UFS2, ZFS) maj´ı tzv. access control lists (ACL´s), kter´edovoluj´ıjemnˇejˇs´ıpˇridˇelov´an´ıpr´av jednotliv´ym uˇzivatel˚um a skupin´am.
API pro soubory • pˇred pouˇzit´ım mus´ıproces kaˇzd´ysoubor nejprve otevˇr´ıt vol´an´ım open() nebo creat(). • otevˇren´esoubory jsou dostupn´epˇres deskriptory soubor˚u (file descriptors), ˇc´ıslovan´eod 0, v´ıce deskriptor˚um˚uˇze sd´ılet jedno otevˇren´ısouboru (m´od ˇcten´ı/z´apis, ukazov´atko pozice) • standardn´ıdeskriptory: – 0 . . . standardn´ıvstup (jen pro ˇcten´ı) – 1 . . . standardn´ıv´ystup (jen pro z´apis) – 2 . . . chybov´yv´ystup (jen pro z´apis) • ˇcten´ıa z´apis z/do souboru: read(), write() • zmˇena pozice: lseek(), zavˇren´ı: close(), informace: stat(), ˇr´ıdic´ıfunkce: fcntl(), pr´ava: chmod(),...
• kaˇzd´afunkce, kter´aalokuje deskriptory (nejen open() a creat(), ale napˇr. i pipe(), dup(), socket()) alokuje vˇzdy voln´edeskriptory s nejniˇzˇs´ım ˇc´ıslem. • proces dˇed´ıotevˇren´esoubory od rodiˇce, tyto soubory nemus´ıznovu otv´ırat. Obvykle (ale ne vˇzdy) proces dostane otevˇren´ealespoˇndeskriptory 0, 1 a 2. • funkce ze souboru stdio.h (napˇr. fopen(), fprintf(), fscanf()) a odkazy na soubory pomoc´ıukazatele na FILE jsou definov´any ve standardn´ıknihovnˇe a pro svoj´ıˇcinnost pouˇz´ıvaj´ıvol´an´ıj´adra (napˇr. open(), write(), read()). My se nebudeme knihovnou stdio zab´yvat.
79 Otevˇren´ısouboru: open() int open(const char *path, int oflag,...); • otevˇre soubor dan´yjm´enem (cestou) path, vr´at´ıˇc´ıslo jeho deskriptoru (pouˇzije prvn´ıvoln´e), oflag je OR-kombinace pˇr´ıznak˚u – O RDONLY/O WRONLY/O RDWR . . . otevˇr´ıt pouze pro ˇcten´ı/ pouze pro z´apis / pro ˇcten´ıi z´apis – O APPEND . . . pˇripojov´an´ına konec – O CREAT . . . vytvoˇrit, kdyˇzneexistuje – O EXCL . . . chyba, kdyˇzexistuje (pouˇzit´ıs O CREATE) – O TRUNC . . . zruˇsit pˇredchoz´ıobsah (pr´avo z´apisu nutn´e) – . . . • pˇri O CREAT definuje tˇret´ıparametr mode pˇr´ıstupov´apr´ava
• pˇri pouˇzit´ı O CREAT se mode jeˇstˇemodifikuje podle umask. • mode nem´adefaultn´ıhodnotu, tj. vezme se to, co je na z´asobn´ıku i kdyˇztento parametr nen´ıpˇr´ıtomen! Pˇr´ıznaky i m´od jsou uloˇzeny v syst´emov´etabulce otevˇren´ych soubor˚u. • pokud se znovu pouˇzije dˇr´ıve vyuˇz´ıvan´apoloˇzka v tabulce deskriptor˚unebo v tabulce otevˇren´ych soubor˚u, vˇse potˇrebn´ese vynuluje (pozice v souboru, flagy deskriptoru, . . . ) • existuj´ıjeˇstˇedalˇs´ınastaviteln´epˇr´ıznaky: – O SYNC (O DSYNC, O RSYNC – nen´ına BSD) ... operace se souborem skonˇc´ıaˇzpo fyzick´em uloˇzen´ıdat (synchronized I/O) – O NOCTTY . . . pˇri otv´ır´an´ıtermin´alu procesem, kter´ynem´aˇr´ıdic´ıter- min´al, se tento termin´al nestane ˇr´ıd´ıc´ım termin´alem procesu – O NONBLOCK . . . pokud nelze ˇcten´ınebo z´apis prov´est okamˇzitˇe, vol´an´ı read()/write() skonˇc´ıs chybou m´ısto zablokov´an´ıprocesu • v pˇr´ıstupov´ych pr´avech se vynuluj´ı ty bity, kter´ejsou nastaven´epomoc´ı umask(). • pro ˇcten´ıa z´apis nelze pouˇz´ıt O RDONLY | O WRONLY, protoˇze implementace pouˇzily 0 pro read-only flag. Norma proto definuje, ˇze aplikace mus´ıpouˇz´ıt pr´avˇejeden z tˇechto tˇr´ıflag˚u. • je moˇzn´eotevˇr´ıt a z´aroveˇnvytvoˇrit soubor pro z´apis tak, ˇze jeho m´od z´apis nedovoluje. Pˇri pˇr´ıˇst´ım otevˇren´ı souboru se ale jiˇz tento m´od uplatn´ı pˇri kontrole pˇr´ıstupu a pro z´apis ho otevˇr´ıt nep˚ujde. Pro O TRUNC tak´eplat´ı, ˇze mus´ıte m´ıt pro dan´ysoubor pr´avo z´apisu.
80 Vytvoˇren´ısouboru
int creat(const char *path, mode t mode ); • open() s pˇr´ıznakem O CREAT vytvoˇr´ısoubor, pokud jeˇstˇe neexistuje. V zadan´ehodnotˇepˇr´ıstupov´ych pr´av se vynuluj´ıbity, kter´ebyly nastaveny pomoc´ıfunkce mode t umask(mode t cmask ); • funkce je ekvivalentn´ıvol´an´ı open(path, O WRONLY|O CREAT|O TRUNC, mode); int mknod(const char *path, mode t mode, dev t dev ); • vytvoˇr´ıspeci´aln´ısoubor zaˇr´ızen´ı. int mkfifo(const char *path, mode t mode ); • vytvoˇr´ıpojmenovanou rouru.
• vol´an´ıvrac´ınejniˇzˇs´ıdeskriptor, kter´yv dan´echv´ıli nebyl otevˇren´ypro proces • open() dok´aˇze otevˇr´ıt regul´arn´ısoubor, zaˇr´ızen´ıi pojmenovanou rouru, ale vytvoˇrit dok´aˇze jen regul´arn´ısoubor; pro ostatn´ıtypy soubor˚uje nutn´epouˇz´ıt speci´aln´ıvol´an´ı. • test, zda soubor existuje, a jeho pˇr´ıpadn´evytvoˇren´ıje atomick´aoperace. Toho se vyuˇz´ıv´apˇri pouˇz´ıv´an´ılock soubor˚u. • speci´aln´ısoubory m˚uˇze vytv´aˇret pouze root, protoˇze se pomoc´ınich definuj´ı pˇr´ıstupov´apr´ava k perifern´ım zaˇr´ızen´ım. • hodnoty pro mode je moˇzn´enal´ezt vˇetˇsinou v manu´alov´estr´ankce pro chmod
81 Cten´ıaˇ z´apis soubor˚u: read(), write()
ssize t read(int fildes, void *buf, size t nbyte ); • z otevˇren´eho souboru s ˇc´ıslem deskriptoru fildes pˇreˇcte od aktu´aln´ıpozice max. nbyte bajt˚udat a uloˇz´ıje od adresy buf. • vrac´ıpoˇcet skuteˇcnˇepˇreˇcten´ych bajt˚u(<= nbyte), 0 znamen´a konec souboru. ssize t write(int fildes, const void *buf, size t nbyte ); – do otevˇren´eho souboru s ˇc´ıslem deskriptoru fildes zap´ıˇse na aktu´aln´ıpozici max. nbyte bajt˚udat uloˇzen´ych od adresy buf. – vrac´ıvelikost skuteˇcnˇezapsan´ych dat (<= nbyte).
• pro UNIX je kaˇzd´ysoubor posloupnost bajt˚ubez dalˇs´ıvnitˇrn´ıstruktury. • chov´an´ı read() a write() z´avis´ına typu souboru (regul´arn´ı, zaˇr´ızen´ı, roura, soket) a na tom, zda je soubor v blokuj´ıc´ım nebo neblokuj´ıc´ım m´odu (flag O NONBLOCK pˇri otevˇren´ısouboru). • vol´an´ı read() vr´at´ınenulov´ypoˇcet bajt˚umenˇs´ıneˇz nbyte, pokud v souboru zb´yv´am´enˇeneˇz nbyte bajt˚u, nebo vol´an´ı bylo pˇreruˇseno sign´alem, nebo soubor je roura, zaˇr´ızen´ıˇci soket a aktu´alnˇeje k dispozici m´enˇeneˇz nbyte bajt˚u. Pˇri neexistenci dat se blokuj´ıc´ı read() zablokuje, dokud se nˇejak´a data neobjev´ı, neblokuj´ıc´ı read() vr´at´ı -1 a nastav´ı errno na EAGAIN. • vol´an´ı write() vr´at´ınenulov´ypoˇcet bajt˚umenˇs´ıneˇz nbyte, jestliˇze se do souboru nevejde v´ıc dat (napˇr. zaplnˇen´ydisk), z´apis je pˇreruˇsen sign´alem nebo je nastaveno O_NONBLOCK a do roury, soketu nebo zaˇr´ızen´ı se vejde pouze ˇc´ast zapisovan´ych dat. Bez O_NONBLOCK se ˇcek´a, dokud se nepodaˇr´ı zapsat vˇse. Pokud nelze aktu´alnˇezapsat nic, blokuj´ıc´ı write() se zablokuje, dokud nen´ımoˇzn´ezapisovat, neblokuj´ıc´ı write() vr´at´ı -1 a nastav´ı errno na EAGAIN. • d˚uleˇzit´ev´yjimky vzhledem k rour´am jsou uvedeny na stranˇe85. • kdyˇz read() nebo write() vr´at´ım´enˇeneˇz nbyte z d˚uvodu chyby, opakovan´e vol´an´ıt´eˇze funkce vr´at´ı -1 a nastav´ık´od chyby v errno. • pˇreruˇsen´ı read(), write() sign´alem dˇr´ıv, neˇzse podaˇr´ıpˇreˇc´ıst, resp. zapsat aspoˇnjeden bajt, zp˚usob´ın´avrat s hodnotou -1 a nastaven´ı errno na EINTR. • pˇr´ıznak otevˇren´ısouboru O_APPEND zajist´ıatomick´yz´apis na konec souboru (pouze na lok´aln´ım disku), tj. kaˇzd´y z´apis se provede na konec souboru.
82 Uzavˇren´ısouboru: close()
int close(int fildes ); • uvoln´ıdeskriptor fildes, pokud to byl posledn´ıdeskriptor, kter´y odkazoval na otevˇren´ısouboru, zavˇre soubor a uvoln´ız´aznam o otevˇren´ısouboru. • kdyˇzje poˇcet odkaz˚una soubor 0, j´adro uvoln´ıdata souboru. Tedy i po zruˇsen´ıvˇsech odkaz˚u(jmen) mohou se souborem pracovat procesy, kter´eho maj´ıotevˇren´y. Soubor se smaˇze, aˇz kdyˇzho zavˇre posledn´ıproces. • kdyˇzse zavˇre posledn´ıdeskriptor roury, vˇsechna zb´yvaj´ıc´ıdata v rouˇre se zruˇs´ı. • pˇri skonˇcen´ıprocesu se automaticky provede close() na vˇsechny deskriptory.
• pokud proces potˇrebuje doˇcasn´ysoubor, m˚uˇze ho vytvoˇrit, ihned smazat a pak s n´ım pracovat pˇres existuj´ıc´ı deskriptor (tento deskriptor lze pˇredat synovsk´ym proces˚um). Kdyˇzje takov´ysoubor zavˇren vˇsemi procesy, j´adro smaˇze jeho data z disku. • i operace close() m˚uˇze selhat. Napˇr. nˇekter´efilesyst´emy zapisuj´ıdata na disk aˇzv okamˇziku zavˇren´ısouboru, kdyˇzz´apis skonˇc´ıchybou, close() vr´at´ı -1. • otev´ır´an´ısoubor˚ua nezav´ır´an´ıje pˇri ukonˇcen´ıpr´ace s nimi vede k alokovan´e pamˇeti, kterou jiˇznem´ame jak uvolnit (ztratili jsme na ni odkaz) – situace kde takto pamˇet’ “ztr´ac´ıme” se naz´yv´a memory leak
83 Pˇr´ıklad: kop´ırov´an´ısoubor˚u #include
• je neefektivn´ıˇc´ıst a zapisovat soubor po jednotliv´ych bajtech, lepˇs´ıje najed- nou zpracov´avat rozumnˇevelk´ebloky. • pokud potˇrebujete pracovat s mal´ymi ˇc´astmi/buffery, je lepˇs´ıpouˇz´ıt stream orintovan´eknihovn´ıfunkce fopen(), fread(), . . . kter´edata vnitˇrnˇebufferuj´ı
84 Pr´ace s pojmenovanou rourou
• nemus´ıb´yt moˇzn´evytvoˇrit FIFO na s´ıt’ov´em filesyst´emu (NFS, AFS) • je nutn´ezn´at s´emantiku otev´ır´an´ıpojmenovan´eroury: – otevˇren´ıroury pouze pro ˇcten´ıse zablokuje do t´edoby, dokud se neobjev´ızapisovatel (pokud jiˇzneexistuje) – otevˇren´ıroury pouze pro z´apis se zablokuje do t´edoby, dokud se neobjev´ıˇcten´aˇr(pokud jiˇzneexistuje) – toto chov´an´ıje moˇzn´eovlivnit flagem O NONBLOCK • s´emantika ˇcten´ıa z´apisu je jeˇstˇeo nˇeco sloˇzitˇejˇs´ı, vˇenujte velkou pozornost pozn´amk´am pod t´ımto slajdem – a je to stejn´ejako u nepojmenovan´eroury (strana 118)
• je moˇzn´eotevˇr´ıt rouru pro z´apis i ˇcten´ıstejn´ym procesem najednou, aniˇzby pˇredt´ım existoval ˇcten´aˇrnebo zapisovatel • pokud rouru nem´aˇz´adn´yproces otevˇrenou pro z´apis, pro okamˇzit´evr´acen´ı deskriptoru pouze pro ˇcten´ı je nutn´e otevˇr´ıt rouru s flagem O NONBLOCK, proces se jinak na rouˇre zablokuje ˇcek´an´ım na zapisovatele. Pozor ale na to, ˇze pokus o ˇcten´ı z roury bez zapisovatele okamˇzitˇevr´at´ı0 jako indikaci konce souboru; proces se nezablokuje ˇcek´an´ım na zapisovatele. Pˇri z´apisu do roury bez ˇcten´aˇre (tj. zapisovatel otevˇrel rouru jeˇstˇev dobˇe, kdy ˇcten´aˇr existoval) poˇsle kernel procesu sign´al EPIPE (“broken pipe”). • v pˇr´ıpadˇeotev´ır´an´ıpouze pro z´apis s O NONBLOCK bez existuj´ıc´ıho ˇcten´aˇre se vr´at´ıchyba a errno se nastav´ına ENXIO. Tato asymetrie je snahou, aby v rouˇre nebyla data, kter´anebudou v kr´atk´edobˇepˇreˇctena – syst´em nem´a zp˚usob, jak uschov´avat data v rouˇre bez ˇcasov´eho omezen´ı. Bez O NONBLOCK flagu se proces zablokuje. • z uveden´eho tedy vypl´yv´a, ˇze pokud chcete vytvoˇrit proces, kter´yˇcek´ana pojmenovan´erouˇre a vykon´av´apoˇzadavky, mus´ıte ji otevˇr´ıt s flagem O RDWR i kdyˇzdo roury nehodl´ate zapisovat; jinak po prvn´ım zablokov´an´ıv open() pˇri ˇcek´an´ına otevˇren´ıroury zapisovatelem by dalˇs´ı vol´an´ı read() pro akcep- tov´an´ıdalˇs´ıho poˇzadavku typicky vr´atilo 0, pokud by n´ahodou roura nebyla mezit´ım pro z´apis otevˇrena dalˇs´ım procesem. • z´apis maxim´aln´ıvelikosti PIPE BUF (limits.h) je zaruˇcen´yjako atomick´y. Napˇr. v OpenSolarisu to je to 5120 bajt˚u, ve FreeBSD 5.4 je to 512 bajt˚u. Pokud zapisujete v´ıce, m˚uˇze write() prov´est ˇc´asteˇcn´yz´apis (a vr´at´ı tak menˇs´ıˇc´ıslo neˇzvelikost dat kter´ase mˇela zapsat). • roura nem´apozici v souboru, z´apis tak vˇzdy pˇrid´av´ana konec.
85 • stejnˇese vzhledem ke ˇcten´ıa z´apisu chov´ai nepojmenovan´aroura, viz strana 118.
Nastaven´ıpozice: lseek()
off t lseek(int fildes, off t offset, int whence ); • nastav´ıpozici pro ˇcten´ıa z´apis v otevˇren´em souboru dan´em ˇc´ıslem deskriptoru fildes na hodnotu offset. • podle hodnoty whence se offset poˇc´ıt´a: – SEEK SET . . . od zaˇc´atku souboru – SEEK CUR . . . od aktu´aln´ıpozice – SEEK END ... od konce souboru • vrac´ıv´yslednou pozici poˇc´ıtanou od zaˇc´atku souboru. • lseek(fildes, 0, SEEK CUR) pouze vr´at´ıaktu´aln´ıpozici.
• lze se pˇresunout i na pozici za koncem souboru. Pokud se pak provede z´apis, soubor se prodlouˇz´ıa v pˇreskoˇcen´eˇc´asti budou sam´e nuly (samotn´e lseek() nestaˇc´ı). Nˇekter´efilesyst´emy takov´ebloky cel´ych nul pro ´usporu m´ısta ne- ukl´adaj´ı. • velikost souboru je moˇzn´ezjistit pomoc´ı lseek(fildes, 0, SEEK END). • nejˇcastˇejˇs´ıoperace s lseek jsou tˇri: nastaven´ıkonkr´etn´ıpozice od zaˇc´atku souboru, nastaven´ıpozice na konec souboru a zjiˇstˇen´ıaktu´aln´ıpozice v sou- boru (0 spoleˇcnˇese SEEK CUR) • pˇri pouˇzit´ı lseek se ˇz´adn´eI/O neprovede, ˇz´adn´ypˇr´ıkaz se nepoˇsle na ˇradiˇc disku • lseek nemus´ıslouˇzit jen pro operace read a write, ale tak´epro n´aslednou operaci lseek • ukl´ad´an´ınul m˚uˇze v´est k probl´em˚um se z´alohami
86 Zmˇena velikosti: truncate()
int truncate(const char *path, off t length ); int ftruncate(int fildes, off t length ); • zmˇen´ıd´elku souboru zadan´eho cestou nebo ˇc´ıslem deskriptoru na poˇzadovanou hodnotu. • pˇri zkr´acen´ısouboru zruˇs´ınadbyteˇcn´adata. • standard ponech´av´anespecifikovan´e, jestli funguje prodlouˇzen´ı souboru (s vyplnˇen´ım pˇridan´eho ´useku nulami). Proto je lepˇs´ı k prodlouˇzen´ısouboru pouˇz´ıt char buf = ’\0’; lseek(fildes, length-1, SEEK_SET); write(fildes, buf, 1);
• zruˇsit veˇsker´yobsah souboru pˇri otevˇren´ıse d´apˇr´ıznakem O TRUNC ve funkci open(). • podrobnosti je tˇreba hledat v manu´alov´estr´ance, napˇr. ve FreeBSD v sekci BUGS nalezneme toto: Use of truncate() to extend a file is not portable.
87 Duplikace deskriptoru: dup(), dup2()
int dup(int fildes ); • duplikuje deskriptor fildes na prvn´ıvoln´ydeskriptor, vr´at´ı nov´ydeskriptor, kter´yodkazuje na stejn´eotevˇren´ısouboru. • ekvivalent fcntl(fildes, F DUPFD, 0); int dup2(int fildes, int fildes2 ); • duplikuje deskriptor fildes na deskriptor fildes2. • ekvivalent close(fildes2); fcntl(fildes, F DUPFD, fildes2);
• prvn´ıvoln´ydeskriptor se pouˇzije i u otev´ır´an´ıa vytv´aˇren´ısoubor˚u, viz strany 80 a 81. • duplikovan´ya p˚uvodn´ıdeskriptor sd´ıl´ıstejn´eotevˇren´ısouboru a tedy i ak- tu´aln´ıpozici a m´od ˇcten´ı/z´apis. • ekvivalent pro dup2 nen´ı zcela ekvivalentn´ı, napˇr. pokud je fildes rovn´y fildes2. V´ıce viz norma.
88 Pˇr´ıklad: implementace shellov´eho pˇresmˇerov´an´ı • $ program < in > out 2>> err close(0); open("in", O_RDONLY); close(1); open("out", O_WRONLY | O_CREAT | O_TRUNC, 0666); close(2); open("err", O_WRONLY | O_CREAT | O_APPEND, 0666); • $ program > out 2>&1 close(1); open("out", O_WRONLY | O_CREAT | O_TRUNC, 0666); close(2); dup(1);
• dalˇs´ıpˇr´ıklad pouˇzit´ı dup() uvid´ıme, aˇzse budeme zab´yvat rourami. • je potˇreba si d´at pozor na stav deskriptor˚u. Druh´ypˇr´ıklad nebude fungovat, kdyˇzbude deskriptor 0 uzavˇren, protoˇze open() vr´at´ıdeskriptor 0 (prvn´ı voln´y) a dup() vr´at´ı chybu (pokus o duplikaci uzavˇren´eho deskriptoru). Moˇzn´eˇreˇsen´ı:
close(1); if((fd = open("out", O WRONLY | O CREAT | O TRUNC, 0666)) == 0) dup(0); close(2); dup(1); if(fd == 0) close(0);
nebo
fd = open("out", O WRONLY | O CREAT | O TRUNC, 0666); if(fd != 1) { dup2(fd, 1); close(fd); } dup2(1, 2);
89 R´ıdic´ıfunkceˇ soubor˚ua zaˇr´ızen´ı: fcntl(), ioctl()
int fcntl(int fildes, int cmd,...); • slouˇz´ıpro duplikaci deskriptor˚u, nastavov´an´ız´amk˚u, testov´an´ıa nastavov´an´ır˚uzn´ych pˇr´ıznak˚usouboru. pˇr´ıklad: zavˇren´ıstandardn´ıho vstupu pˇri spuˇstˇen´ıprogramu (vol´an´ıtypu exec) fcntl(0, F SETFD,FD CLOEXEC); int ioctl(int fildes, int request,...); • rozhran´ıpro ˇr´ıdic´ıfunkce perifern´ıch zaˇr´ızen´ı • pouˇz´ıv´ase jako univerz´aln´ırozhran´ıpro ovl´ad´an´ı zaˇr´ızen´ı, kaˇzd´e zaˇr´ızen´ıdefinuje mnoˇzinu pˇr´ıkaz˚u, kter´ym rozum´ı.
• moˇzn´ehodnoty cmd ve funkci fcntl(): – F DUPFD . . . duplikace deskriptoru – F GETFD . . . zjiˇstˇen´ıpˇr´ıznak˚udeskriptoru (FD CLOEXEC – uzavˇren´ıpˇri exec). FD CLOEXEC je jedin´yflag pro deskriptory, definovan´yv normˇe UNIX 03. – F SETFD . . . nastaven´ıpˇr´ıznak˚udeskriptoru – F GETFL . . . zjiˇstˇen´ım´odu ˇcten´ı/z´apis a pˇr´ıznak˚uotevˇren´ısouboru (jako u open()) – F SETFL . . . nastaven´ıpˇr´ıznak˚uotevˇren´ısouboru (O APPEND, O DSYNC, O NONBLOCK, O RSYNC, O SYNC). Nemohu nastavit pˇr´ıznaky pro ro/rw a ani pˇr´ıznaky pro vytvoˇren´ı, zkr´acen´ınebo exkluzivn´ıpˇr´ıstup k souboru. – F GETLK, F SETLK, F SETLKW . . . nastavov´an´ız´amk˚u • je d˚uleˇzit´esi uvˇedomit, ˇze jsou dva druhy pˇr´ıznak˚u – pˇr´ıznak(y) pro soubo- rov´ydeskriptor a pˇr´ıznaky pro otevˇren´ysoubor – tj. pˇr´ıznaky jsou uloˇzen´e ve dvou r˚uzn´ych tabulk´ach. • perifern´ı zaˇr´ızen´ı podporuj´ı ˇcten´ı a z´apis dat pomoc´ı read(), write() a mapov´an´ıdat do pamˇeti (mmap()), veˇsker´edalˇs´ıoperace se zaˇr´ızen´ım (napˇr. nastaven´ıparametr˚u, zamˇcen´ınebo eject) se dˇelaj´ıfunkc´ı ioctl(). • pˇri nastavov´an´ıpˇr´ıznak˚unejdˇr´ıv vˇzdy zjistˇete, jak´ebyly pˇredt´ım. I kdyˇz jste si jisti, ˇze v dan´echv´ıli jsou nulov´ea je tedy moˇzn´eprov´est fcntl(fd, O APPEND), nem˚uˇzete vˇedˇet, co se m˚uˇze zmˇenit (napˇr´ıklad o p´ar ˇr´adk˚uv´yˇse nˇejak´yflag pˇrid´ate, aniˇzbyste vˇedˇeli, ˇze jste ovlivnˇeni k´odem dole). Tedy vˇzdy pouˇzijte napˇr´ıklad toto:
90 flags = fcntl(fd, F_GETFL); if (fcntl(fd, F_SETFL, flags | O_APPEND) == -1) ...
. . . a podobnˇepro odebr´an´ıflagu – je ˇspatn´eˇreˇsen´ınastavit hodnot˚uflag˚una nulu, m´ısto toho je tˇreba pouˇz´ıt bitov´eho jedniˇckov´eho doplˇnku pˇr´ısluˇsn´eho flagu
Informace o souboru: stat()
int stat(const char *path, struct stat *buf ); int fstat(int fildes, struct stat *buf ); • pro soubor zadan´ycestou, resp. ˇc´ıslem deskriptoru, vr´at´ı strukturu obsahuj´ıc´ıinformace o souboru, napˇr.: – st ino . . . ˇc´ıslo i-uzlu – st dev . . . ˇc´ıslo zaˇr´ızen´ıobsahuj´ıc´ıho soubor – st uid, st gid . . . vlastn´ık a skupina souboru – st mode . . . typ a pˇr´ıstupov´apr´ava – st size, st blksize, st blocks . . . velikost souboru v bajtech, velikost bloku a poˇcet blok˚u – st atime, st mtime, st ctime . . . ˇcasy posledn´ıho pˇr´ıstupu, modifikace souboru a modifikace i-uzlu – st nlink . . . poˇcet odkaz˚una soubor
• metadata jsou informace o souboru – tedy m´od, ˇcasy pˇr´ıstupu, d´elka, vlastn´ık a skupina atd. Nepatˇr´ımezi nˇeskuteˇcn´adata souboru, a ani jm´eno, kter´e nen´ıuloˇzeno v r´amci dan´eho souboru, ale v adres´aˇri ˇci v adres´aˇr´ıch. • metadata je moˇzn´epˇreˇc´ıst, i kdyˇzproces nem´apr´ava pro ˇcten´ıobsahu sou- boru. • touto funkc´ınez´ısk´am flagy deskriptoru ani flagy z pole tabulky otevˇren´ych soubor˚uv syst´emu, zde jde o informace ohlednˇesouboru uloˇzen´eho na pamˇe- t’ov´em m´ediu. • c time nen´ı ˇcas vytvoˇren´ısoubor (creation time), ale ˇcas zmˇeny (change time) • norma nespecifikuje poˇrad´ıpoloˇzek ve struktuˇre ani nezakazuje pˇridat dalˇs´ı
91 Informace o souboru (2)
• pro typ souboru jsou v
• typ a pr´ava souboru jsou uloˇzena spoleˇcnˇev st_mode, proto existuj´ızmiˇno- van´amakra. • S IFMT specifikuje tu ˇc´ast bit˚u, kter´ejsou vˇenovan´etypu souboru, makra pro jednotliv´etypy pak nejsou masky, ale hodnoty, takˇze test na typ souboru je nutn´eudˇelat takto: (st mode & S IFMT == S IFREG). Vˇsechna makra jsou v normˇe, takˇze jejich pouˇz´ıv´an´ım zaruˇc´ıme pˇrenositeln´yk´od.
92 Nastaven´ıˇcas˚usouboru
int utime(const char *path, const struct utimbuf *times ); • nastav´ıˇcas posledn´ımodifikace souboru a ˇcas posledn´ıho pˇr´ıstupu k souboru. • nelze zmˇenit ˇcas posledn´ımodifikace i-uzlu. • volaj´ıc´ıproces mus´ım´ıt pr´avo z´apisu pro soubor.
• tuto funkci pouˇz´ıvaj´ıhlavnˇekop´ırovac´ıa archivaˇcn´ıprogramy, aby zajistily stejn´eˇcasy kopie a origin´alu. • shellov´erozhran´ıpro funkci utime() pˇredstavuje pˇr´ıkaz touch.
93 Test pˇr´ıstupov´ych pr´av: access()
int access(const char *path, int amode ); • otestuje, zda volaj´ıc´ıproces m´ak souboru path pr´ava dan´a OR-kombinac´ıkonstant v amode: – R_OK . . . test pr´ava na ˇcten´ı – W_OK . . . test pr´ava na z´apis – X_OK . . . test pr´ava na spuˇstˇen´ı – F_OK ... test existence souboru • na rozd´ıl od stat(), v´ysledek z´avis´ına RUID a RGID procesu • toto vol´an´ıse ned´apouˇz´ıt bezpeˇcnˇe, proto ho nikdy nepouˇz´ıvejte procesu
• vol´an´ı access() aplikuje mechanismus testov´an´ı pˇr´ıstupov´ych pr´av k za- dan´emu souboru pro volaj´ıc´ıproces a vr´at´ıv´ysledek. • funkce access() vol´an´ıbyla pro setuid proces, aby si mohl ovˇeˇrit, zda uˇzivatel bˇeˇz´ıc´ıdan´ysetuid proces by mˇel za norm´aln´ıch okolnost´ık pˇr´ısluˇsn´emu sou- boru pˇr´ıstup. Z toho vypl´yv´a, ˇze toto vol´an´ıje security hole – mezi testem a n´aslednou akc´ıse soubor m˚uˇze zmˇenit, coˇzproces nem˚uˇze nikdy oˇsetˇrit. Reˇsen´ımˇ je vr´atit se zp´atky k re´aln´ym UID/GID a pˇr´ıstup vyzkouˇset.
94 Nastaven´ıpˇr´ıstupov´ych pr´av int chmod(const char *path, mode t mode ); • zmˇen´ıpˇr´ıstupov´apr´ava souboru path na hodnotu mode. • tuto sluˇzbu m˚uˇze volat pouze vlastn´ık souboru nebo superuˇzivatel (root). int chown(const char *path, uid t owner, gid t group ); • zmˇen´ıvlastn´ıka a skupinu souboru path. Hodnota -1 znamen´a zachovat vlastn´ıka, resp. skupinu. • mˇenit vlastn´ıka m˚uˇze jen superuˇzivatel, aby uˇzivatel´enemohli obch´azet nastaven´equoty t´ım, ˇze sv´esoubory pˇredaj´ı nˇekomu jin´emu. • bˇeˇzn´yuˇzivatel m˚uˇze mˇenit skupinu sv´ych soubor˚ua mus´ıpˇritom patˇrit do c´ılov´eskupiny.
• parametr mode zde samozˇrejmˇeneobsahuje typ souboru, jako tomu je napˇr´ı- klad u vol´an´ı stat(). Hodnoty mode viz chmod(2). • pokud nejsem vlastn´ık, nemohu celkem logicky zmˇenit m´od ani u souboru s nastaven´ym pˇr´ıstupem rw-rw-rw- • v nˇekter´ych implementac´ıch m˚uˇze vlastn´ık souboru pˇredat vlastnictv´ınˇeko- mu jin´emu, napˇr. v IRIXu je chov´an´ı chown() nastaviteln´ejako parametr j´adra. • nen´ıbˇeˇzn´evolat funkci chmod() z uˇzivatelsk´ych aplikac´ı, na to se pouˇz´ıvaj´ı flagy u vol´an´ı open(), hlavn´ıpouˇzit´ıje v aplikaci chmod(1)
95 Manipulace se jm´eny soubor˚u
int link(const char *path1, const char *path2 ); • vytvoˇr´ınov´yodkaz (poloˇzku adres´aˇre) path2 na soubor path1. Funguje pouze v r´amci jednoho svazku. int unlink(const char *path ); • zruˇs´ıodkaz na soubor. Po zruˇsen´ıposledn´ıho odkazu na soubor a uzavˇren´ısouboru vˇsemi procesy je soubor smaz´an. int rename(const char *old, const char *new ); • zmˇen´ıjm´eno souboru (pˇresnˇeodkazu na soubor) z old na new. Funguje pouze v r´amci jednoho svazku.
• vol´an´ı link() vytv´aˇr´ıhardlinky, tj. zobrazen´ıze jm´ena souboru na ˇc´ıslo i- uzlu. C´ıslaˇ i-uzl˚ujsou jednoznaˇcn´apouze v r´amci svazku, proto pro linky mezi filesyst´emy je nutn´epouˇz´ıt symlinky.
• parametr path2 nesm´ıexistovat, tedy nelze takto pˇrejmenov´avat • unlink() nefunguje na adres´aˇre • shellov´ypˇr´ıkaz mv pouˇz´ıv´a rename pro pˇresuny v r´amci jednoho svazku. Pˇresun souboru mezi filesyst´emy vyˇzaduje nejprve soubor zkop´ırovat a pak smazat origin´al vol´an´ım unlink. • rename() funguje nad symlinky, ne nad soubory, na kter´esymlink ukazuje
96 Symbolick´elinky
int symlink(const char *path1, const char *path2 ); • vytvoˇr´ısymbolick´ylink path2 → path1. • c´ıl symbolick´eho linku m˚uˇze b´yt i na jin´em svazku, popˇr´ıpadˇe nemus´ıv˚ubec existovat. int readlink(const char *path, char *buf, size t bufsize ); • do buf d´amax. bufsize znak˚uz cesty, na kterou ukazuje symlink path. • vr´at´ıpoˇcet znak˚uuloˇzen´ych do buf. • obsah buf nen´ızakonˇcen nulou (znakem ’\0’)!
• shellov´ypˇr´ıkaz ln vol´a symlink() nebo link(), podle toho, jestli je pouˇzit pˇrep´ınaˇc -l nebo ne. • smaz´an´ıhardlinku nesmaˇze soubor, pokud na nˇej vede jeˇstˇejin´yhardlink. Naopak soubor (poloˇzku adres´aˇre i data) je moˇzn´esmazat, i kdyˇzna nˇej ukazuj´ınˇejak´esymlinky. • readlink() je pouˇziteln´yv situaci, pokud chci smazat soubor, na kter´ydan´y symlink ukazuje • bufsize se typicky d´av´ao 1 menˇs´ı neˇzvelikost bufferu, to pro ukonˇcen´ı znakem ’\0’
97 Manipulace s adres´aˇri int mkdir(const char *path, mode t mode ); • vytvoˇr´ınov´ypr´azdn´yadres´aˇr, (bude obsahovat pouze poloˇzky ’.’ a ’..’). int rmdir(const char *path ); • smaˇze adres´aˇr path. Adres´aˇrmus´ıb´yt pr´azdn´y. DIR*opendir(const char *dirname ); struct dirent *readdir(DIR*dirp ); int closedir(DIR*dirp ); • slouˇz´ık sekvenˇcn´ımu proch´azen´ıadres´aˇr˚u. • struktura dirent obsahuje poloˇzky – d_ino . . . ˇc´ıslo i-uzlu – d_name . . . jm´eno souboru
• poloˇzky adres´aˇre nejsou nijak uspoˇr´ad´any, readdir() je m˚uˇze vracet v libo- voln´em poˇrad´ı. • v nˇekter´ych implementac´ıch (napˇr. FreeBSD) lze adres´aˇrotevˇr´ıt pro ˇcten´ı(ne pro z´apis) jako norm´aln´ısoubor a ˇc´ıst ho pomoc´ı read(), ale je tˇreba zn´at jeho vnitˇrn´ıorganizaci. Proto je readdir() pro zpracov´an´ıobsahu adres´aˇre lepˇs´ı neˇz read(), kter´yvrac´ıraw data adres´aˇre. Kromˇetoho, norma nevyˇzaduje, aby adres´aˇrbylo moˇzn´eˇc´ıst funkc´ı read(), Linux to napˇr´ıklad nedovol´ı. • readdir() je stavov´afunkce. Pro vr´acen´ıse na zaˇc´atek je moˇzn´epouˇz´ıt funkci rewinddir(). S vl´akny pak pouˇz´ıvat readdir r(), protoˇze struktura dirent je statick´a. • d ino nen´ımoc uˇziteˇcn´e, protoˇze v pˇr´ıpadˇe, kdy dan´yadres´aˇrje mount point, tak ukazuje na adres´aˇr, na kter´yje dalˇs´ıfilesyst´em namontov´an, ne na koˇren namontovan´eho filesyst´emu • rmdir nefunguje na nepr´azn´yadres´aˇr, je moˇzn´epouˇz´ıt napˇr´ıklad toto: system("rm -r xxx")
98 Pˇr´ıklad: proch´azen´ıadres´aˇre
int main(int argc, char *argv[]) { int i; DIR *d; struct dirent *de; for(i = 1; i < argc; i++) { d = opendir(argv[i]); while(de = readdir(d)) printf("%s\n", de->d_name); closedir(d); } exit(0); }
• pˇr´ıkaz ls je zaloˇzen na takov´eto smyˇcce, nav´ıc prov´ad´ınapˇr. tˇr´ıdˇen´ıjmen soubor˚ua zjiˇst’ov´an´ıdalˇs´ıch informac´ıpomoc´ı stat(). • konec adres´aˇre se pozn´atak, ˇze readdir() vr´at´ı NULL. To vˇsak vr´at´ı i v pˇr´ıpadˇe, pokud nastala chyba. V takov´em pˇr´ıpadˇeje k´od chyby v promˇenn´e errno, v pˇr´ıpadˇeprvn´ım je errno nezmˇenˇena. Proto by errno mˇelo b´yt vˇzdy nastaven´ena nulu pˇred vol´an´ım readdir(). V pˇr´ıkladu tomu tak nen´ı, protoˇze z d˚uvodu m´alo m´ısta nekontrolujeme errno v˚ubec.
99 Aktu´aln´ıadres´aˇrprocesu
• kaˇzd´yproces m´asv˚uj aktu´aln´ı(pracovn´ı) adres´aˇr, v˚uˇci kter´emu jsou ud´av´any relativn´ıcesty k soubor˚um. Poˇc´ateˇcn´ı nastaven´ı pracovn´ıho adres´aˇre se dˇed´ıod otce pˇri vzniku procesu. int chdir(const char *path ); int fchdir(int fildes ); • nastav´ınov´ypracovn´ıadres´aˇrprocesu. char *getcwd(char *buf, size t size ); • uloˇz´ıabsolutn´ıcestu k aktu´aln´ımu adres´aˇri do pole buf, jeho d´elka (size) mus´ıb´yt aspoˇno 1 vˇetˇs´ıneˇzd´elka cesty.
• funkci fchdir() se pˇred´av´adeskriptor z´ıskan´yvol´an´ım open() na adres´aˇr. • funkce getcwd() m˚uˇze vr´atit jinou cestu neˇztu, po kter´ejsme se do aktu´al- n´ıho adres´aˇre dostali, jesliˇze ˇc´ast cesty v chdir() byl symlink nebo doˇslo k pˇresunu (pˇrejmenov´an´ı) nˇekter´eho adres´aˇre na cestˇeod koˇrene. U souˇcasn´ych ˚uby se to ale uˇzst´at nemˇelo.
100 Obsah
• ´uvod, v´yvoj UNIXu a C, program´atorsk´en´astroje • z´akladn´ıpojmy a konvence UNIXu a jeho API • pˇr´ıstupov´apr´ava, perifern´ızaˇr´ızen´ı, syst´em soubor˚u • manipulace s procesy, spouˇstˇen´ıprogram˚u • sign´aly • synchronizace a komunikace proces˚u • s´ıt’ov´akomunikace • vl´akna, synchronizace vl´aken • ??? - bude definov´ano pozdˇeji, podle toho kolik zbyde ˇcasu
101 Pamˇet’ procesu v uˇzivatelsk´em reˇzimu
text data bss adresovateln´e uˇziv. programem nelze adresovat z´asobn´ık { oblast user uˇziv. programem
• text ... k´od programu • data . . . inicializovan´epromˇenn´e • sekce text a data jsou uloˇzeny ve spustiteln´em souboru • bss . . . neinicializovan´epromˇenn´e(bss poch´az´ız assembleru IBM 7090 a znamen´a,,block started by symbol”). Za bˇehu programu tvoˇr´ısekce data a bss dohromady datov´ysegment procesu. Velikost datov´eho segmentu lze mˇenit pomoc´ısyst´emov´ych vol´an´ı brk() a sbrk(). • (uˇzivatelsk´y) z´asobn´ık . . . automatick´epromˇenn´e, parametry funkc´ı, n´avra- tov´eadresy. Kaˇzd´yproces m´adva z´asobn´ıky, jeden pro uˇzivatelsk´yreˇzim a jeden pro reˇzim j´adra. Uˇzivatelsk´yz´asobn´ık procesu automaticky roste podle potˇreby (neplat´ı, pokud se pouˇz´ıvaj´ıvl´akna). • oblast user (u-area) . . . obsahuje informace o procesu pouˇz´ıvan´ej´adrem, kter´e nejsou potˇrebn´e, kdyˇzje proces odloˇzen na disku (poˇcet otevˇren´ych soubor˚u, nastaven´ıoˇsetˇren´ısign´al˚u, poˇcet segment˚usd´ılen´epamˇeti, argumenty pro- gramu, promˇenn´eprostˇred´ı, aktu´aln´ıadres´aˇr, atd.). Tato oblast je pˇr´ıstupn´a pouze pro j´adro, kter´evˇzdy vid´ıpr´avˇejednu u-oblast patˇr´ıc´ıpr´avˇebˇeˇz´ıc´ımu procesu. Dalˇs´ıinformace o procesu, kter´ej´adro m˚uˇze potˇrebovat i pro jin´y neˇzpr´avˇebˇeˇz´ıc´ıproces, nebo i kdyˇzje proces odloˇzen, jsou ve struktuˇre proc. Struktury proc pro vˇsechny procesy jsou st´ale rezidentn´ıv pamˇeti a viditeln´e v reˇzimu j´adra.
102 Pamˇet’ procesu v reˇzimu j´adra
text j´adra data a bss j´adra (tabulky, promˇenn´e, apod.)
struktura user beˇz´ıc´ıho procesu
extern struct user u; z´asobn´ık j´adra
• proces se dostane do reˇzimu j´adra bud’ pˇr´ıchodem pˇreruˇsen´ıvyvolan´eho proce- sorem (v´ypadek str´anky, nezn´am´ainstrukce,...), ˇcasovaˇcem (v pravideln´ych intervalech je potˇreba aktivovat pl´anovaˇcproces˚u), perifern´ım zaˇr´ızen´ım, nebo instrukc´ısynchronn´ıho pˇreruˇsen´ı(standardn´ı knihovna takto pˇred´av´a ˇr´ızen´ıj´adru, aby obslouˇzilo syst´emov´evol´an´ı). • v pamˇeti je pouze jedna kopie k´odu a dat j´adra, sd´ılen´avˇsemi procesy. K´od j´adra je vˇzdy cel´yrezidentn´ıv pamˇeti, nen´ıodkl´ad´an na disk. • text j´adra . . . k´od j´adra operaˇcn´ıho syst´emu, zaveden´ypˇri startu syst´emu a rezidentn´ıv pamˇeti po celou dobu bˇehu syst´emu. Nˇekter´eimplementace umoˇzˇnuj´ıpˇrid´avat funkˇcn´ımoduly do j´adra za bˇehu (napˇr. pˇri pˇrid´an´ınov´eho zaˇr´ızen´ıse do j´adra dynamicky pˇrid´anov´yovladaˇc), nen´ıproto tˇreba kv˚uli kaˇzd´ezmˇenˇeregenerovat j´adro a restartovat syst´em. • data a bss j´adra . . . datov´estruktury pouˇz´ıvan´ej´adrem, souˇc´ast´ıje i u-oblast pr´avˇebˇeˇz´ıc´ıho procesu. • z´asobn´ık j´adra . . . samostatn´ypro kaˇzd´yproces, je pr´azdn´y, jestliˇze je proces v uˇzivatelsk´em reˇzimu (a tedy pouˇz´ıv´auˇzivatelsk´y z´asobn´ık).
103 Pamˇet’ov´esegmenty procesu
a segs read only struct as text s as shared s prev s next read/write data private struct proc read/write z´asobn´ık private
read/write sd´ılen´apamˇet’ shared
• kaˇzd´yproces m´atˇri z´akladn´ısegmenty (pamˇet’ov´esegmenty, nemluv´ıme o hardwarov´ych segmentech): – text – data – z´asobn´ık • d´ale lze do adresov´eho prostoru pˇripojit segmenty sd´ılen´epamˇeti (shmat()) nebo soubory (mmap()). • text je sd´ılen vˇsemi procesy, kter´eprov´ad´ıstejn´yk´od. Datov´ysegment a z´asobn´ık jsou priv´atn´ıpro kaˇzd´yproces. • z´akladn´ım rysem t´eto architektury je tzv. memory object, coˇzje abstrakce mapov´an´ımezi kusem pamˇeti a m´ıstem, kde jsou data norm´alnˇeuloˇzena (tzv. backing store nebo data object). Takov´em´ısto uloˇzen´ım˚uˇze b´yt napˇr´ıklad swap nebo soubor. Adresov´yprostor procesu je pak mnoˇzina mapov´an´ına r˚uzn´edatov´eobjekty. Existuje i anonymn´ıobjekt, kter´ynem´am´ısto trval´eho uloˇzen´ı(pouˇz´ıv´ase napˇr´ıklad pro z´asobn´ık). Fyzick´apamˇet’ pak slouˇz´ıjako cache pro data tˇechto namapovan´ych datov´ych objekt˚u. • tato zde velmi hrubˇepopsan´aarchitektura se naz´yv´aVM (od Virtual Me- mory), a objevila se v SunOS 4.0. Na t´eto architektuˇre je zaloˇzena architek- tura viru´aln´ıpamˇeti v SVR4. V´ıce informac´ıviz [Vahalia], p˚uvodn´ıˇcl´anek z roku 1987 pˇredstavuj´ıc´ıtuto architekturu: Gingell, R. A., Moran J. P., Shannon, W. A. – Virtual Memory Architecture in SunOS nebo pˇredn´aˇska o operaˇcn´ıch syst´emech na MFF ve ˇctvrt´em (?) roˇcn´ıku.
104 Virtu´aln´ıpamˇet’
pamˇet’ pamˇet’ pamˇet’ pamˇet’ procesu 1 procesu 2 procesu 3 procesu 4