Programov´an´ıv UNIXu

(NSWI015)

verze: 24. ˇr´ıjna2017

() 2011 – 2017 Vladim´ırKotal (c) 2005 – 2011, 2016 – 2017 Jan Pechanec (c) 1999 – 2004 Martin Beran

SISAL MFF UK, Malostransk´en´am.25, 118 00 Praha 1

• Toto jsou ofici´aln´ımateri´alypro v´yuku pˇredmˇetu Programov´an´ıv UNIXu (k´odpˇredmˇetuNSWI015) na Matematicko-fyzik´aln´ıfakultˇeUniverzity Kar- lovy. • Tyto materi´alyjsou uveˇrejnˇeny pod licenc´ı Creative Commons BY-NC-SA 3.0. Soubory k uk´azkov´ympˇr´ıklad˚umuveden´ev´yˇsejsou Public Domain, po- kud v nich nen´ıuvedeno jinak. • Tento pˇredmˇetje 2/1, cviˇcen´ıbude jednou za dva t´ydny. • Vˇsechny informace, kter´ebudete potˇrebovat, a materi´alyk pˇredn´aˇscejsou na http://mff.devnull.cz/, vˇcetnˇeaktu´aln´ıverze tˇechto pozn´amkov´ych slajd˚u (http://mff.devnull.cz/pvu/slides/). Dˇr´ıve, neˇzzaˇcnetemateri´alypou- ˇz´ıvat, pˇresvˇedˇctese, ˇzenen´ınovˇejˇs´ıverze! • Uk´azkov´epˇr´ıkladyjsou na http://mff.devnull.cz/pvu/src/, pokud se budu v pozn´amk´ach odkazovat na konkr´etn´ıpˇr´ıklad,link zde uveden´yslouˇz´ıjako koˇrenov´yadres´aˇr.

• Je potˇrebase zapsat na cviˇcen´ıv SISu. • Z´apoˇcetje za z´apoˇctov´yprogram. • Zkouˇska m´ap´ısemnoua ´ustn´ıˇc´ast. • Zkouˇsetse bude to, co bude odpˇredneseno(kromˇet´ematna vyplnˇen´ıpˇr´ıpadnˇe zbyl´ehoˇcasu).Vˇetˇsinainformac´ıje ve slajdech, ale ˇradad˚uleˇzit´ych podrob- nost´ım˚uˇzechybˇet.

1 • Pˇredpoklady: – Uˇzivatelsk´aznalost UNIXu, programov´an´ıv shellu na ´urovni pˇredn´aˇsky ,,Uvod´ do UNIXu” (NSWI095) – 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ˇe 242. Upo- zornˇen´ına chyby pros´ımpos´ılejtena kontakty, kter´enajdete na v´yˇseuveden´e str´ance.

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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

• Budeme se zab´yvat hlavnˇeprincipy UNIXu a programov´an´ım pro pouze v jazyce C. • Pˇredn´aˇska je pˇrev´aˇznˇeo syst´emov´ych vol´an´ıch, tj. rozhran´ımmezi uˇzivatelsk´ymprostorem a j´adrem.

• Pˇripopisu API se budeme drˇzetnormy Single UNIX Specification, version 4 (SUSv4). Syst´emy, kter´etuto specifikaci podporuj´ı,mohou pouˇz´ıvat oznaˇcen´ı UNIX V7. Pˇredchoz´ıverzi SUSv3 splˇnuj´ıposledn´ıverze syst´em˚uSolaris, AIX, HP-UX a Mac OS X na r˚uzn´ych architektur´ach (http://www.opengroup.org/ openbrand/register/xy.htm).

• Pro konkr´etn´ıpˇr´ıklady budu pouˇz´ıvat vˇetˇsinou syst´emy FreeBSD a .

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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

Literatura v ˇceˇstinˇe

1. Skoˇcovsk´y,L.: Principy a probl´emy operaˇcn´ıhosyst´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ˇcebnicejazyka C. 2 d´ıly. Kopp, Cesk´eˇ Budˇejovice, 2004 (4., respektive 2. pˇrepracovan´evyd´an´ı)

3 Ohlednˇeunixu doporuˇcujisp´ıˇseliteraturu v anglick´emjazyce.

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´ıcenebo 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´acese soubory a s procesy, Sys- tem V IPC, nepopisuje napˇr.vl´aknaa s´ıtˇe. 4. O Linuxu bylo samozˇrejmˇev ˇceˇstinˇevyd´anomnoho 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 . 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´ymialgoritmy, strukturami apod., nejsou to kniho o programov´an´ıpod t´ımto syst´emem.

1. Skvˇel´akniha, zab´yv´ase obecn´ymimyˇslenkami UNIXu a porovn´av´asyst´emy SVR4.2, 4.4BSD, Solarix 2.x a Mach. 12/2005 mˇelovyj´ıtdruh´e,doplnˇen´e vyd´an´ı.Po nˇekolika letech ˇcek´an´ıpˇrestalodruh´evyd´an´ıfigurovat v listingu na amazon.com, a tedy se budeme muset zˇrejmˇesm´ıˇrits t´ım,ˇzenevyjde. 2. Klasick´akniha o UNIXu, popis struktury a funkc´ıj´adraUNIX System V Rel. 2, ˇc´asteˇcnˇei 3; pˇrestoˇzeje to kniha z dneˇsn´ıhopohledu jiˇzzastaral´a, lze ji poˇr´adjednoznaˇcnˇedoporuˇcit,protoˇzeto 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´ıhosyst´emu UNIX, SAS.

4 3. Popis struktury a funkc´ıj´adraFreeBSD 5.2; tato kniha navazuje na klasickou knihu The Design and Implementation of the 4.4 BSD Operating System od stejn´ehoautora (resp. jeden ze ˇctyˇr,uveden´yjako prvn´ı). 4. Nejlepˇs´ıkniha o operaˇcn´ımsyst´emu Solaris. Obsahuje podrobn´einformace o tom, jak tento syst´emfunguje 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´ıhoprojektu.

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´ajako spo- jen´ıknih 1 a 3, m˚uˇzeto b´ytnˇekdynaopak v´yhodou. Tuto knihu jednoznaˇcnˇe doporuˇcuji,pokud chcete nˇecokupovat a chcete m´ıtpro zaˇc´atekjen jednu knihu. Pokud bych ji mˇelcharakterizovat jednou vˇetou,bylo by to, ˇzeautor vid´ıa dok´aˇze uk´azatsouvislosti, coˇzje velmi vz´acn´avlastnost. 3. Klasick´akniha o s´ıt’ov´emprogramov´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.

5 6. Podrobn´ypopis jednotliv´ych funkc´ı (v Linuxu bˇeˇznˇene zcela dostaˇcuj´ıc´ı; manu´alov´estr´ankyv tomto syst´emu jsou ˇcastohorˇs´ıkvality neˇzu syst´em˚u ostatn´ıch).

7. Kniha, kter´ase neveˇslana slajd a kter´apˇrekraˇcujeobsah t´etopˇredn´aˇsky: Gallmeister, B. R.: POSIX.4 Programmers Guide: Programming for the Real World, O’Reilly; 1st edition, 1995. V´yborn´akniha s kr´asnou ob´alkou o real-time rozˇs´ıˇren´ıch POSIXu. Viz tak´estrany 155a 159.

... 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ˇetena http://www.amazon.com/ a zadejte kl´ıˇcov´eslovo “unix”. Pokud byste z Amazonu nˇecokupovali, dejte pozor na to, ˇzemnoho knih m´aaktu- alizovan´avyd´an´ıi po nˇekolika m´aloletech, nˇekdyi levnˇejˇs´ıneˇzta p˚uvodn´ı, kter´ajsou vˇsakst´alena skladu a v on-line nab´ıdce;tak at’ zbyteˇcnˇenekoup´ıte starˇs´ıvyd´an´ıneˇzto aktu´aln´ı.Nav´ıcse vyplat´ızkontrolovat i u pˇr´ısluˇsn´eho vydavatelstv´ı,ˇzenen´ıv brzk´edobˇenapl´anov´anovyd´an´ınov´e– tato informace nˇekdyna Amazonu je, nˇekdyne.

... na Amazonu se m˚uˇzevyplatit nakoupit knihy z druh´eruky, protoˇzejsou ˇcasto v´yraznˇelevnˇejˇs´ıneˇzknihy nov´e.Probl´emje, ˇzevˇetˇsinounen´ımoˇzn´eje poslat pˇr´ımodo CR,ˇ ale mus´ıv´amje nˇekdopˇ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: http://oreilly.com/openbook/opensources/book/index.html ... mnoho materi´al˚una webu; ˇcastovˇsakobsahuj´ıc´ıne zcela pˇresn´einformace

• Kapitola o BSD Unixu z Open Sources napsan´aMarshallem Kirk McKusic- kem je opravdu v´yborn´a.

6 (Pre)historie UNIXu

• 1925 – Bell Telephone Laboratories – v´yzkumv 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´emsoubor˚upro PDP-7 • 1970 – Multi-cs ⇒ Uni-cs ⇒ Uni-x • 1971 – UNIX V1, a portov´anna PDP-11 • prosinec 1971 – prvn´ıedice UNIX Programmer’s Manual

• AT&T = American Telephone and Telegraph Company • Multics byl syst´em,kter´yv´yznamnˇeovlivnil dalˇs´ıv´yvoj operaˇcn´ıch syst´em˚u. Obsahoval mnoho v t´edobˇeinovativn´ıch myˇslenek,z nichˇzale ne vˇsechny byly pˇrij´ım´any kladnˇe. V´yznamnˇeovlivnil pr´avˇeUNIX, kter´ymnoho myˇslenek pˇrevzala jeho nedostatky se naopak snaˇzil napravit. Hlavn´ırozd´ılbyl asi ten, ˇzeUNIX byl navrˇzenjako mnohem jednoduˇsˇs´ısyst´em,neˇzMultics.

• 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´aleaktivnˇevyv´ıjel(virtu´aln´ıpamˇet’, multiprocesory, . . . ), aˇzdo roku 1985. Posledn´ı instalace Multics-u fungovala na kanadsk´emMinisterstvu obrany (Canadian Department of National Defence) a syst´embyl napˇr´ıklad jeˇstˇe aktivnˇepouˇz´ıv´anpro vojensk´eoperace bˇehemv´alky v Persk´em z´alivu.Defi- nitivn´ıshutdown byl proveden 31. ˇr´ıjna2000. V´ıceinformac´ıje moˇzn´enal´ezt na http://www.multicians.org. • pˇredpoˇc´atkem pr´acena v´yvojov´emprostˇred´ıpro PDP-7 napsal Thompson program Space Travel, kter´ybyl vyvinut na jin´emprostˇred´ı(Honeywell 635) a na p´ascepˇrenesenna PDP-7. • celkem bylo 10 edic´ıtohoto manu´alu,koresponduj´ıc´ıdeseti verz´ımUNIXu vznikl´ych v BTL.

• UNIX V1 nemˇelvol´an´ı pipe !!!

7 • manu´alpro verzi 1: http://man.cat-v.org/unix-1st/ Stoj´ıza to nahl´ednout, jak jeho struktura ovlivnila vzhled dneˇsn´ıch manu´alov´ych str´anek.

• za povˇsimnut´ıstoj´ı,ˇzeUNIX je zhruba o 10 let starˇs´ıneˇzDOS • syst´emMultics mˇel9 hlavn´ıch c´ıl˚u,jak pops´anov ˇ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ˇehsyst´emu. • Multics byl napsan´yv jazyce PL/I ( #1), tedy dˇr´ıve neˇzbyl UNIX pˇrepsan´ydo C ! • Multicsu byl v roce 1980 udˇelenjako prvn´ımu syst´emu level B2. Po nˇekolik let to byl jedin´ysyst´ems t´ımto bezpeˇcnost´ımlevelem. • GE byla zaloˇzenav 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ˇcnostipokr´yvaj´ı mnoho oblast´ı, vˇcetnˇedod´avkyjednoho 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ˇceprod´avaly za ceny pˇresmili´on.To byla tak´estrategie fy DEC - pojem computer tehdy znamenal drahou vˇec, potˇrebuj´ıc´ıs´ala t´ymlid´ı,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ˇsinaod 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.

8 Historie UNIXu, pokraˇcov´an´ı

• ´unor1973 – UNIX V3 obsahoval cc pˇrekladaˇc(jazyk C byl vytvoˇren Dennisem Ritchiem pro potˇreby UNIXu) • ˇr´ıjen1973 – UNIX byl pˇredstaven veˇrejnostiˇcl´ankem The UNIX Timesharing System na konferenci ACM • listopad 1973 – UNIX V4 pˇreps´ando 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´anna 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ˇzena1947. UNIX pˇredstavili Ken Thompson a Dennis Ritchie. • akt pˇreps´an´ıUNIXu do jazyka C byl moˇzn´anejv´yznamnˇejˇs´ımmo- mentem v historii tohoto syst´emu ⇒ UNIX mohl b´ytmnohem jed- noduˇsejiportov´anna jin´earchitektury • na verzi 6 je zaloˇzenalegend´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´aleportovaly na 286 (Intel) a 386 (SCO, 1987). Na webu je moˇzn´e naj´ıtzaj´ımav´einformace popisuj´ıc´ıtuto dobu a tehdy kladn´yvztah Micro- softu k UNIXu. • UNIX V7 mˇelcca 188 tis´ıcˇr´adekzdrojov´ehok´oduv cca 1100 souborech (zjiˇstˇenopomoc´ı find, wc a awk pˇressoubory se jm´enem *.[cshy]). • pokud v´asv´ıce zaj´ım´ahistorie unixu, pod´ıvejte se na Wikipedii na heslo “unix” a skrz odkazy m´atena dlouho co ˇc´ıst. • V roce 1973 byl UNIX v´ıceuˇzivatelsk´ysyst´em(konta s hesly) s podporou pro multiprocessing s ochranou proces˚ua str´ankov´an´ım.Mˇelsign´aly, roury, hie- rarchick´ysyst´emsoubor˚us mount pointy, souborov´apr´ava (User/group/other r/w/x), hard linky, zaˇr´ızen´ı pˇr´ıstupn´ajako soubory. Kernel byl naps´anv jazyku C a v pamˇeti zab´ıral jeho obraz 26 Kilobyt˚u.Pro pr´acise sou- bory slouˇzilysyst´emov´avol´an´ı open(), close(), read(), write(), seek(),

9 pipe(). K manipulaci s procesy vol´an´ı fork(), exec(), wait(), exit(). Celkem bylo 48 syscall˚u, z nich existuje 35 do dneˇsn´ıdoby.

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´ehodo Berkeley se vyv´ıj´ı BSD Unix (Berkeley Software Distribution) verze 3.0; posledn´ıverze 4.4 v roce 1993 • 1982 AT&T, vlastn´ıkBTL, m˚uˇzevstoupit na trh poˇc´ıtaˇc˚u (zak´az´anood 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´ajilv´yvoj OS Linux, verze j´adra1.0 byla dokonˇcenav r. 1994

• UNIX je univerz´aln´ıoperaˇcn´ısyst´emfunguj´ıc´ına ˇsirok´eˇsk´alepoˇc´ıtaˇc˚uod embedded a handheld syst´em˚u(Linux), pˇres osobn´ı poˇc´ıtaˇceaˇ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´etodobˇ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´amciBT. Na tˇechto r˚uzn´ych verz´ıch je pr´avˇezaloˇzena verze System III. Z´ajemceo v´ıceinformac´ıodkazuji na web. • UNIX se rozˇstˇepilna dvˇehlavn´ı vˇetve: AT&T a BSD, jednotliv´ı v´yrobci pˇrich´azelis vlastn´ımimodifikacemi. Jednotliv´eklony od sebe navz´ajem pˇreb´ıralyvlastnosti. • System V R4 mˇelcca 1.5 milionu ˇr´adekzdrojov´ehok´oduv cca 5700 souborech (zjiˇstˇenopomoc´ı find, wc a awk pˇressoubory se jm´enem *.[cshy]). • Univerzita v Berkeley z´ıskala jako jedna z prvn´ıch licenci UNIXu v roce 1974. Bˇehemnˇekolika let studenti (jedn´ımz nich byl Bill Joy, pozdˇejˇs´ızakladatel firmy a autor C-shellu) vytvoˇriliSW bal´ık Berkeley Soft- ware Distribution (BSD) a prod´avali ho v roce 1978 za $50. Tyto poˇc´ateˇcn´ı

10 verze BSD obsahovaly pouze SW a utility (prvn´ı verze: Pascal pˇrekladaˇc, editor ex), ne syst´emani ˇz´adn´ejeho zmˇeny. To pˇriˇsloaˇzs verz´ı3BSD. verze 4BSD vznik´aroku 1980 jiˇzjako projekt financovan´yagenturou DARPA a veden´yBillem Joyem. Trp´ıprobl´emy spojen´ymis nedostateˇcn´ymv´ykonem a vznik´atak vyladˇen´ysyst´em4.1BSD dod´avan´yod roku 1981. • 4.1BSD mˇelob´ytp˚uvodnˇe5BSD, ale pot´e,co AT&T vzneslo n´amitky, ˇzeby si z´akazn´ıcimohli pl´est5BSD se syst´ememSystem V, pˇreˇsloBSD na ˇc´ıslov´an´ı 4.xBSD. Bˇeˇznouvˇec´ıbylo, ˇzeneˇzps´atvlastn´ık´od,v´yvoj´aˇriz Berkeley se radˇejinejdˇr´ıve pod´ıvali kolem, co je jiˇzhotov´e.Tak BSD napˇr´ıkladpˇrevzalo virtu´aln´ıpamˇet’ z Machu a nebo NFS-kompatibiln´ık´odvyvinut´yna jedn´e kanadsk´euniverzitˇe. • v´yrobci hardware dod´avali varianty UNIXu pro sv´epoˇc´ıtaˇcea komercializace tak jeˇstˇezhorˇsilasituaci co t´yˇcediverzifikace totoho syst´emu

• v 80-t´ych letech se proto zaˇcalyobjevovat snahy o standardizaci. Standard ˇr´ık´a,jak m´avypadat syst´emnavenek (pro uˇzivatele, program´atora a spr´avce), nezab´yv´ase implementac´ı.C´ılemje pˇrenositelnostaplikac´ıi uˇzivatel˚u.Vˇsech- ny syst´emy totiˇzz d´alkyvypadaly jako UNIX, ale pˇribliˇzˇs´ımprozkoum´an´ı se liˇsilyv mnoha d˚uleˇzit´ych vlastnostech. System V a BSD se napˇr.liˇsilyv pouˇzit´emfilesyst´emu, s´ıt’ov´earchitektuˇrei v architektuˇrevirtu´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,ˇzeby 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´emOSF/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´emje postaven´yna mikroj´adruMach. Po akvizici Digi- talu Compaqem byl syst´empˇrejmenov´anna Tru64 a s t´ımto jm´enemje d´ale podporov´anfirmou Hewlett-Packard, kter´ase v roce 2002 s Compaqem spo- jila. Mezit´ımfirmy AT&T a Sun kontrovaly zaloˇzen´ımUNIX 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´ımunixem”. • OSF a UI se staly velk´ymirivaly, ale velmi rychle se stˇretlys neˇcekan´ym protivn´ıkem - s firmou Microsoft. • (1992) 386BSD zaloˇzen´e na Networking Release 2 ; Bill Jolitz vytvoˇril 6 chybˇej´ıc´ıch soubor˚ua dal tak dohromady funkˇcn´ıBSD syst´empro i386. Tento syst´emse stal z´aklademsyst´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´asledujerozpuˇstˇen´ıCSRG, kter´a skoro 20 let pilotovala v´yvoj BSD vˇetve. V´ıce jiˇzzm´ınˇen´akapitola o BSD Unixu.

11 Souˇcasn´eUNIXy

Hlavn´ıkomerˇcn´ıunixov´esyst´emy: • Sun Microsystems: SunOS (nen´ıjiˇzd´alevyv´ıjen), Solaris • Apple: macOS (dˇr´ıve Mac OS X) • SGI: IRIX (nen´ıjiˇzd´alevyv´ıjen) • IBM: AIX • HP: HP-UX, Tru64 UNIX (Compaq) • SCO: SCO Unix • Xinuos (kdysi Novell): UNIXware Open source: • FreeBSD, NetBSD, OpenBSD • Linux distribuce

• Striktnˇetechnicky vzato se jako UNIX m˚uˇzeoznaˇcovat pouze syst´em,kter´y proˇselcertifikac´ıSingle Unix Specification. Z v´yˇseuveden´ehoseznamu by to byly 4 operaˇcn´ısyst´emy, kter´ebyly registrov´any jako UNIX 03 na r˚uzn´ych ar- chitektur´ach (http://www.opengroup.org/openbrand/register/). Ostatn´ısys- t´emy, kter´enebyly certifikov´any, se oznaˇcuj´ıjako Unix-like, aˇckoliv v mnoha pˇr´ıpadech splˇnuj´ıvˇetˇsin˚upoˇzadavk˚ustandardu. Bˇeˇznˇese nicm´enˇepouˇz´ıv´a oznaˇcen´ıUnix pro obˇedvˇeskupiny. • 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´adaltelevizn´ı/filmov´ypr˚umysl (napˇr. Pixar studio na IRIXu vznikly filmy jako A Bug’s Life, Toy Story a dalˇs´ı). A na AIX napˇr´ıkladbˇeˇzel Deep Blue, paraleln´ısuperpoˇc´ıtaˇc,kter´yv roce 1997 porazil v ˇsestifascinuj´ıc´ıch z´apasech 3.5 ku 2.5 ´uˇraduj´ıc´ıhovelmistra ˇsachu Garriho Kasparova. Jin´ymislovy – kaˇzd´ysyst´emm´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 byl projekt vznikl´yv ˇcervnu 2005 a byl zaloˇzenna podmnoˇzinˇe zdrojov´ych text˚uv´yvojov´everze Solarisu (kernel, knihovny, pˇr´ıkazy). Distri- buce vzeˇsl´ez komunity jsou napˇr´ıkladLiveCD BeleniX, SchilliX a Nexenta. Pˇrestoˇzeprojekt OpenSolaris jiˇzd´alenepokraˇcuje,existuje open source fork a na nˇemzaloˇzen´edistribuce SmartOS a OpenIndiana.

• pozor na to, ˇzeLinux je pouze j´adro,ne syst´em,na rozd´ıl tˇrebaod Fre- eBSD. Illumos je nˇecomezi t´ım,j´adro+ drivery, z´akladn´ıpˇr´ıkazy a knihovny,

12 a v bin´arn´ı podobˇeto m´anˇecopˇres 100MB. V obou pˇr´ıpadech je tedy spr´avn´epouˇz´ıvat spojen´ı “Linux (Illumos) distribuce”, kdyˇzse bav´ıme o cel´emsyst´emu.

• kaˇzd´akomerˇcn´ı varianta vych´azelaz jednoho ze dvou hlavn´ıch syst´em˚u– UNIX V nebo BSD, a pˇrid´avala si sv´evlastnosti. D´ıkymnoha verz´ımUNIXu tak vznik´avelk´ypoˇcetr˚uzn´ych standard˚u(strana 14). Nakonec se vˇetˇsina v´yrobc˚ushodla na nˇekolika z´akladn´ıch.

• graf zn´azorˇnuj´ıc´ıhistorii unixov´ych syst´em˚ua z´avislostimezi nimi na 19-ti A4 listech ve form´atuPS/PDF je k nalezen´ına http://www.levenez.com/unix/

13 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´eriestandard˚uorganizace IEEE znaˇcen´aP1003.xx, postupnˇeje pˇrej´ım´avrcholov´ynadn´arodn´ıorg´anISO • XPG (X/Open Portability Guide) – doporuˇcen´ıkonsorcia X/Open, kter´ebylo zaloˇzenov r. 1984 pˇredn´ımiv´yrobci platforem typu UNIX • Single UNIX Specification – standard organizace The Open Group, vznikl´ev roce 1996 slouˇcen´ımX/Open a OSF – dnes Version 4 (SUSv4) – splnˇen´ıje nutnou podm´ınkou pro uˇzit´ıobchodn´ıhon´azvuUNIX

• z´akladn´ıinformace je, ˇzeoblast standard˚ut´ykaj´ıc´ıse unixov´ych syst´em˚uje vˇecznaˇcnˇesloˇzit´aa na prvn´ıpohled velmi nepˇrehledn´a. • AT&T dovolila v´yrobc˚umnaz´yvat svoji komerˇcn´ıUNIX variantu “System V” pouze pokud splˇnovala podm´ınkystandardu SVID. AT&T tak´epublikovala System V Verification Suite (SVVS), kter´eovˇeˇrilo,zda dan´ysyst´emodpov´ıd´a standardu. • POSIX (Portable Operating System Interface) je standardizaˇcn´ısnaha orga- nizace IEEE (Institute of Electrical and Electronics Engineers). • SUSv4 je spoleˇcn´ystandard The Open Group, IEEE (Std. 1003.1, 2008 Edi- tion) a ISO (ISO/IEC 9945-2008). • Pro certifikaci operaˇcn´ıhosyst´emu na Single Unix Specification je nutn´eaby syst´em(na dan´earchitektuˇre, napˇr.64-bit x86) proˇselsadou test˚u.V´ysledky test˚ujsou pak vyhodnoceny. Testy samotn´ejsou sdruˇzeny do tzv. test suites, coˇzjsou sady automatick´ych test˚u,kter´eprojdou syst´ema zjist´ıjestli splˇnuje rozhran´ıdan´enormou. Pro SUSv3 je takov´ych test suites cca 10. • Rozhran´ıspecifikovan´enormou POSIX.1-2008 se dˇel´ına 4 z´akladn´ıskupiny: XSH (System Interfaces), XCU (Shell and Utilities), XBD (Base definitions). Z nich je co do poˇcturozhran´ınejobs´ahlejˇs´ıXSH, kter´apopisuje v´ıceneˇz 1000 rozhran´ı. • Skupiny rozhran´ıPOSIXu spolu se skupinou Xcurses, kter´aje souˇc´ast´ıSingle Unix Specification (ale nikoliv souˇc´astPOSIX b´azev normˇeIEEE Std 1003.1- 2001) zahrnuj´ıcelkem 1742 rozhran´ı,kter´etvoˇr´ıSingle Unix Specification

14 (2003). Tabulky rozhran´ı SUS je moˇzn´ez´ıskat zde: http://www.unix.org/ version3/inttables.pdf • komerˇcn´ı UNIXy vˇetˇsinousleduj´ı Single UNIX Specification, splnˇen´ı t´eto normy je pr´avˇepodm´ınkou pro uˇzit´ın´azvuUNIX (znaˇcka UNIX 98 odpov´ıd´a SUSv2, znaˇcka UNIX 03 odpov´ıd´aSUSv3, SUSv4 je UNIX V7 - nepl´ests historick´ymV7 UNIX). Je postavena na b´aziPOSIXu. My se budeme drˇzet SUSv4. Popis datov´ych struktur a algoritm˚uj´adrav tomto materi´alubude vˇetˇsinouvych´azet ze System V Rel. 4.

• na Solarisu je obs´ahl´amanu´alov´astr´anka standards(5), kde m˚uˇzetena jed- nom m´ıstˇenal´eztmnoho informac´ıt´ykaj´ıc´ıse standard˚u.Jednotliv´epˇr´ıkazy splˇnuj´ıc´ıdanou normu jsou nav´ıcum´ıstˇeny do vyhrazen´ych adres´aˇr˚u.Napˇr. program tr je v adres´aˇr´ıch /usr/xpg4/bin/ a /usr/xpg6/bin/, v kaˇzd´emje verze pˇr´ıkazu splˇnuj´ıc´ıdanou normu. Na pˇrep´ınaˇcea chov´an´ıdan´enormou se pak lze spolehnout napˇr.pˇripsan´ıshellov´ych skript˚u.

• opˇetna Solarisu, pod´ıvejte se na hlaviˇckov´ysoubor /usr/include/sys/fea- ture tests.h

POSIX

• tvrzen´ı“tento syst´emje POSIX kompatibiln´ı”ned´av´aˇz´adnou konkr´etn´ıinformaci – asi podporuje POSIX1990 a moˇzn´ai nˇecodalˇs´ıho (co?) • dotyˇcn´ybud’ nev´ıco je POSIX nebo si mysl´ı,ˇzeto nev´ıtevy • jedin´arozumn´areakce je ot´azka “jak´yPOSIX?” • POSIX je rodina standard˚u • prvn´ımdokumentem je IEEE Std POSIX1003.1-1988, pozdˇeji po vzniku dalˇs´ıch rozˇs´ıˇren´ıneform´alnˇeodkazovan´yjako POSIX.1 • posledn´ıverze POSIX.1 je IEEE Std 1003.1, 2004 Edition – obsahuje v sobˇejiˇzi to, co dˇr´ıve definoval POSIX.2 (Shell and Utilities) a r˚uzn´a,dˇr´ıve samostatn´arozˇs´ıˇren´ı

• prvn´ımdokumentem je IEEE Std POSIX1003.1-1988, dˇr´ıve oznaˇcovan´ypros- tˇejako POSIX, pak odkazovan´yjako POSIX.1, protoˇzePOSIXem se nyn´ı m´ın´ı sada vz´ajemnˇesouvisej´ıc´ıch standard˚u. POSIX.1 v t´edobˇeobsaho- val programovac´ı API, tj. pr´aces procesy, sign´aly, soubory, ˇcasovaˇciatd. S mal´ymizmˇenamibyl pˇrevzatorganizac´ıISO (ISO 9945-1:1990 ), a je ozna- ˇcovan´yi jako POSIX1990. IEEE oznaˇcen´ıje IEEE Std POSIX1003.1-1990. Tento standard byl s´amo sobˇevelk´y´uspˇech, ale st´alejeˇstˇenespojoval t´abory

15 System V a BSD, protoˇzev sobˇenapˇr´ıkladnezahrnoval BSD sockety nebo IPC (semafory, zpr´avy, sd´ılen´apamˇet’) ze System V. Souˇc´ast´ıstandardu je i “POSIX conformance test suite (PCTS)”, kter´yje volnˇek dispozici. • oznaˇcen´ıPOSIX vymyslel Richard Stallman, tedy ˇclovˇek,kter´yv roce 1983 zaloˇzilGNU projekt. • d˚uleˇzit´aroˇzˇs´ıˇren´ık IEEE Std 1003.1-1990 (jsou souˇc´ast´ıIEEE Std 1003.1, 2004 Edition): – IEEE Std 1003.1b-1993 Realtime Extension, neform´alnˇezn´am´yjako POSIX.4, protoˇzeto bylo jeho p˚uvodn´ı oznaˇcen´ı pˇredpˇreˇc´ıslov´an´ım; j´abudu toto rozˇs´ıˇren´ı nˇekdytak´enaz´yvat POSIX.4. Vˇetˇsinatohoto rozˇs´ıˇren´ıje nepovinn´a,takˇzetvrzen´ı“syst´empodporuje POSIX.1b” m´a jeˇstˇehorˇs´ıvypov´ıdac´ıhodnotu neˇz“syst´emje POSIX kompatibiln´ı”,a to prakticky nulovou. Jedin´apovinn´aˇc´astPOSIX.4 je mal´edoplnˇen´ık sign´al˚umoproti POSIX1990. Je proto nutn´evˇzdyuv´est, co z POSIX.4 je implementov´ano– napˇr.sd´ılen´apamˇet’, semafory, real-time sign´aly, zamyk´an´ıpamˇeti,asynchronn´ıI/O, ˇcasovaˇceatd. – IEEE Std 1003.1c-1995 Threads, viz strana 213. – IEEE Std 1003.1d-1999 Additional Realtime Extensions – IEEE Std 1003.1j-2000 Advanced Realtime Extensions, viz strana 233. – ... • standardy POSIX je moˇzn´enal´eztna http://www.open-std.org/. HTML verze je volnˇek prohl´ıˇzen´ı,za PDF verzi se plat´ı.

Jazyk C

• t´emˇeˇrcel´yUNIX je napsan´yv C, pouze nejniˇzˇs´ıstrojovˇe z´avisl´aˇc´astv assembleru ⇒ pomˇernˇesnadn´apˇrenositelnost • navrhl Dennis Ritchie z Bell Laboratories v roce 1972. • n´asledn´ıkjazyka B od Kena Thomsona z Bell Laboratories. • vytvoˇrenjako prostˇredekpro pˇrenosOS 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

16 • 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´ema pracn´emprocesu byl v roce 1989 standard koneˇcnˇehotov, a je zn´am´ynejˇcastˇejijako “ANSI C”, pˇr´ıpadnˇejako C89 (napˇr´ıkladpˇrekladaˇcpro tuto normu se v Sun Studiu jmenuje c89, jelikoˇz i to samotn´ejm´enoprogramu mus´ıb´ytpodle normy). Druh´evyd´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ˇzeb´ytnˇekdyoznaˇcov´ani 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´amciISO a vznik´aISO 9899:1999, ˇcastˇejioznaˇcovan´yjako C99. V roce 2000 pak naopak tento standard pˇrevzalANSI. • rozd´ılymezi C89 a C99 jsou mimo jin´ezahrnut´ıinline funkc´ı,definic´ıpro- mˇenn´ych napˇr´ıkladi do for konstrukce, jednoˇr´adkov´ych koment´aˇr˚upomoc´ı //, nov´ych funkc´ıjako snprintf apod. • specifikaci C standardu a mnoho dalˇs´ıch otevˇren´ych standard˚uje moˇzn´e nal´eztna http://www.open-std.org/.

Form´aty dat

• poˇrad´ıbajt˚u– z´avis´ına architektuˇrepoˇ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´adkytextov´ych soubor˚ukonˇc´ıv UNIXu znakem LF (nikoliv CRLF). Vol´an´ı putc(’\n’) tedy p´ıˇsepouze jeden znak. • big endian – SPARC, MIPS, s´ıt’ov´epoˇrad´ıbajt˚u • little endian – Intel

17 • velk´ypozor na v´ystupy program˚utypu hexdump, kter´edefaultnˇevypisuj´ısou- bor v 16-ti bitov´ych ˇc´ıslech, coˇzsv´ad´ıvidˇetsoubor jinak, neˇzjak je opravdu zapsan´yna disku; viz pˇr´ıklad(i386, FreeBSD). Prvn´ıˇc´ıslov souboru je znak ’i’, kter´yale reprezentuje niˇzˇs´ıch 8 bit˚u16-ti bitov´ehoˇc´ısla, takˇzepokud vyp´ıˇsemeprvn´ı2 bajty jako short integer, mus´ıb´ytreprezentace znaku ’i’ (tj. ˇc´ıslo69) aˇzza 6a. Obdobnˇepro ’kl’.

$ echo -n ijkl > test $ hexdump test 0000000 6a69 6c6b 0000004

je samozˇrejmˇemoˇzn´epouˇz´ıtjin´yform´atv´ystupu:

$ hexdump -C test 00000000 69 6a 6b 6c 00000004

• UNIX norma pˇr´ıkaz hexdump nem´a,ale definuje od (octal dump), takˇzezde je jeho hexdumpu ekvivalentn´ıform´atv´ypisuna SPARCu (Solaris); vˇsimnˇete si zmˇeny oproti v´ypisuna i386 !

$ od -tx2 test 0000000 696a 6b6c 0000004

Deklarace a definice funkce

• K&R – deklarace n´avratov´y_typindentifik´ator(); – definice n´avratov´y_typindentifik´ator(par[,par...]) typ par;... { /* tˇelofunkce */ }

• ANSI – deklarace n´avratov´y_typindentifik´ator(typpar [,typ par...]); – definice n´avratov´y_typindentifik´ator(typpar [,typ par...]) { /* tˇelofunkce */ }

18 • pouˇz´ıvejte pouze novˇejˇs´ı(ANSI) typ deklarac´ıa vˇzdydeklarujte prototypy funkc´ı,tj. inkludujte hlaviˇckov´esoubory. V´yjimkou m˚uˇzeasi jen to, pokud budete pracovat s k´odem,kter´ybyl napsan´ypodle K&R.

• r˚uzn´ymiz´apisydeklarac´ı se dost´av´amerovnou i k r˚uzn´ymstyl˚umpsan´ı zdrojov´ych text˚u.Nˇekter´e syst´emy to pˇr´ıliˇs neˇreˇs´ı (Linux), jin´e syst´emy maj´ıvelmi striktn´ıpravidla pro psan´ızdrojov´ych text˚u(napˇr.Solaris, viz on-line C Style and Coding Standards for SunOS: http://mff.devnull.cz/ pvu/common/cstyle.ms.pdf). Snad kaˇzd´yUNIXov´ysyst´emm´aprogram in- dent(1), kter´yv´ampomoc´ıpˇrep´ınaˇc˚upˇreform´atujejak´ykoli C zdrojov´ytext do poˇzadovan´ehov´ystupu.

C style

• vˇeczd´anlivˇepodˇradn´a,pˇritomextr´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 dohodnou (pokud je alespoˇntrochu rozumn´y),ale aby se dohodli. Jednotn´ya dobˇrezvolen´ystyl ˇsetˇr´ıˇcasa br´an´ızbyteˇcn´ymchyb´am.

19 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, ˇzedobr´ystyl zdrojov´ych k´od˚uje i vizitkou program´atora. Kdyˇzse v r´amcipˇrij´ımac´ıch pohovor˚uodevzd´avaj´ıi uk´azkov´ek´ody, tak hlavn´ı d˚uvod pˇrekvapivˇenen´ıten, aby se zjistilo, ˇzev´amdan´yprogram funguje. Uprava´ samotn´ehozdrojov´ehotextu je jedn´ımz kriteri´ı,protoˇzeto pˇrenesenˇe m˚uˇzesvˇedˇciti o dalˇs´ıch skuteˇcnostech – nˇekdonapˇr.bude odhadovat, ˇze pokud p´ıˇseteneˇcist´ya neupraven´yk´od,tak jste moˇzn´ajeˇstˇenepracovali na nˇeˇcemopravdu sloˇzit´emˇcinˇeˇcem zahrnuj´ıc´ımspolupr´aci s v´ıceprogram´atory, protoˇzev tom pˇr´ıpadˇeje rozumnˇeˇcist´yk´odjednou z podm´ınek´uspˇechu a jednou ze zkuˇsenost´ı,kter´ez takov´espolupr´acevych´azej´ı.Toto je samozˇrejmˇe zˇc´astisubjektivn´ın´azor,ale ˇcist´ymk´odemnic nezkaz´ıte,minim´alnˇenekaz´ıte oˇcisv´ymcviˇc´ıc´ım.

• informace o C stylu pouˇz´ıvan´empro zdrojov´ek´odySolarisu, vˇcetnˇeskriptu, kter´yv´amzdroj´akyzkontroluje a upozorn´ına pˇr´ıpadn´enedostatky, je moˇzn´e nal´eztna http://mff.devnull.cz/pvu/common/cstyle.html. Pokud budete do- drˇzovat tento styl pˇripsan´ızkouˇskov´ych pˇr´ıklad˚u,uˇsetˇr´ıtemi t´ımpr´acipˇri vyhodnocov´an´ı.Obecnˇeje dobr´e,abyste si zkusili, co je to ps´atk´odpodle nˇejak´ehokonkr´etn´ıhostylu, a ten pro dan´y,,projekt” dodrˇzet. • bohuˇzelani v´yˇseuveden´yskript nen´ı vˇsemocn´y.Je zaloˇzen´yna kontrole pomoc´ıregul´arn´ıch v´yraz˚u,takˇzetˇrebaten assembler styl ze slajdu projde bez chyby, protoˇzebez skuteˇcn´eanal´yzyk´odunen´ımoˇzn´e(?) kontrolovat spr´avn´eodsazov´an´ı.Vˇseostatn´ıje na nˇem,dle cstyle skriptu, korektn´ı.

20 Utility

cc, c99∗, gcc† pˇrekladaˇcC CC, g++† pˇrekladaˇcC++ ld spojovac´ıprogram (linker) ldd pro zjistˇen´ız´avislost´ıdynamick´ehoobjektu cxref ∗ kˇr´ıˇzov´eodkazy ve zdrojov´ych textech v C sccs∗, rcs,cvs spr´ava verz´ızdrojov´ehok´odu make∗ ˇr´ızen´ıpˇrekladupodle z´avislost´ı ar∗ spr´ava knihoven objektov´ych modul˚u dbx, gdb† debuggery prof, gprof † profilery ∗ SUSv3 † GNU

SUSv3

• standardn´ıpˇr´ıkaz vol´an´ıkompil´atorua linkeru C je c99 (podle ISO normy pro C z roku 1999)

• cb (C program beautifier) nen´ı • pro spr´avuverz´ıje sccs • debuggery a profilery nejsou

21 Konvence pro jm´enasoubor˚u

*.c jm´enazdrojov´ych soubor˚uprogram˚uv C *.cc jm´enazdrojov´ych soubor˚uprogram˚uv C++ *.h jm´enahlaviˇckov´ych soubor˚u(header˚u) *.o pˇreloˇzen´emoduly (object files) a.out jm´enospustiteln´ehosouboru (v´ysledek´uspˇeˇsn´ekompilace)

/usr/include koˇrenstromu 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 k´odfunkc´ı pouˇzit´ych z knihovny stane souˇc´ast´ıv´ysledn´ehospustiteln´ehoprogramu. Dnes se uˇzmoc nepouˇz´ıv´a. sd´ılen´eknihovny – program obsahuje pouze odkaz na knihovnu, pˇrispuˇstˇen´ıpro- gramu se potˇrebn´eknihovny naˇctoudo pamˇetize soubor˚u *.so a pˇrilinkuj´ı.

• dnes se vˇetˇsinou pouˇz´ıvaj´ısd´ılen´eknihovny, protoˇzenezab´ıraj´ıtolik diskov´eho prostoru (knihovna je na disku jednou, nen´ısouˇc´ast´ıkaˇzd´ehospustiteln´eho souboru) a snadnˇejise upgraduj´ı(staˇc´ıinstalovat novou verzi knihovny, nen´ı tˇreba pˇrelinkovat programy). Posledn´ı verze Solarisu uˇznapˇr´ıklad v˚ubec neobsahuje libc.a, d´ıkyˇcemuˇzjiˇzprogram´atornem˚uˇzevytvoˇritstatickou bin´arku,aniˇzby mˇeldostateˇcn´eznalosti syst´emu. • nˇekdyse bez statick´ych knihoven neobejdeme. V nˇekter´ych situac´ıch nen´ı moˇzn´epouˇz´ıtknihovny dynamick´e,spustiteln´esoubory jsou takzvan´e standa- lone binaries a pouˇzit´ınaleznou napˇr´ıkladpˇribootov´an´ıoperaˇcn´ıhosyst´emu.

22 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ˇelitzdrojov´ytext programu do nˇekolika modul˚u,kter´eobsahuj´ıpˇr´ıbuzn´efunkce a tyto moduly se pak mohou pˇrekl´adatzvl´aˇst’ (dokonce kaˇzd´ymodul m˚uˇzeb´ytv jin´emjazyce a pˇrekl´ad´an jin´ympˇrekladaˇcem).V´yhodou je jednak urychlen´ıpˇrekladu(pˇrekl´adaj´ıse vˇzdyjen moduly zmˇenˇen´eod posledn´ıhopˇ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´ychmo- dul˚u, jeˇzobsahuj´ık´odprogramu (vˇcetnˇevol´an´ılok´aln´ıch funkc´ı),ale nam´ısto vol´an´ıextern´ıch funkc´ıobsahuj´ıjen tabulku jejich jmen.

• po f´azipˇrekladunastupuje 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´ymiknihovnami resp. mezi moduly navz´ajem. • pouˇzit´estatick´eknihovny jsou zkop´ırov´any do spustiteln´ehosouboru. Na sd´ılen´eknihovny jsou ve spustiteln´emsouboru pouze odkazy a linkuje je runtime linker pˇrikaˇzd´emspuˇstˇen´ıprogramu. V´ıceviz dynamick´ylinker na stranˇe 35. • pomoc´ı parametr˚ulinkeru lze urˇcit,zda se budou pouˇz´ıvat statick´enebo dynamick´eknihovny. Zdrojov´yk´odje v obou pˇr´ıpadech stejn´y.Existuje i mechanismus (dlopen, dlsym. . . ), pomoc´ıkter´ehose za bˇehu programu vy- bere 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´ıtomnapˇr´ısluˇsn´afunkcionalita a pokud ne, zachovat se podle toho. V´ıcena stranˇe 144.

23 Pˇreklad jednoho modulu (preprocesor)

main.c #include #include ”mydef.h” main() main.i { int puts(char *s); puts(MSG); } extern int var a; /usr/include/stdio.h main()

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 (include) soubor˚ua vy- nech´av´akoment´aˇre.

• v´ystuppreprocesoru lze z´ıskat pomoc´ı cc -E pˇr´ıpadnˇepˇr´ımozavol´an´ım cpp, nemus´ıto b´yt ale vˇzdytot´eˇzprotoˇzenˇekter´epˇrekladaˇcemaj´ıpreprocesor integrov´anv sobˇe.Preprocesor m˚uˇzetesamozˇrejmˇepouˇz´ıvat i pro jin´epro- jekty, kter´es pˇreklademzdrojov´ych soubor˚uv jazyce C nemus´ım´ıtv˚ubec nic spoleˇcn´eho. • pouˇzit´ıpreprocesoru se m˚uˇzevelmi hodit v situaci, kdy potˇrebujetezas´ahnout do ciz´ıhok´odu,pln´ehopodm´ı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ˇrihled´an´ıp˚uvodce chyby v´ampr´avˇem˚uˇzehodnˇepomoci samostatn´ehozpracov´an´ıvstupn´ıho souboru pomoc´ıpreprocesuru, kde probl´emjiˇzvˇetˇsinourozpozn´atesnadno.

• cpp (nebo cc -E v´amdok´aˇzena standardn´ıchybov´yv´ystupzobrazit i cel´y strom vkl´adan´ych soubor˚u,coˇzopˇetpˇripodm´ıneˇcn´ych pˇrekladech m˚uˇzeb´yt velmi uˇziteˇcn´avˇec.Staˇc´ıpro to pouˇz´ıtvolbu -H a pˇresmˇerovat v´ystupdo /dev/null ˇc´ımˇzdostanete pouze hierarchii vkl´adan´ych hlaviˇckov´ych sou- bor˚u.

24 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

• obr´azekv´yˇseje pˇr´ıkladv´ystupupro i386 platformu (32-bit, AT&T syntax). • pˇrekladz C do assembleru

• v´ystupt´etof´azepˇrekladulze z´ıskat pomoc´ı cc -S.

25 Pˇrekladjednoho 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

• opˇetpˇr´ıkladv´ystupupro i386 platformu (32-bit). • pˇrekladz assembleru do strojov´ehok´odu

• objektov´ymodul je v´ysledkem pˇr´ıkazu cc -c.

26 Kompil´ator

• vol´an´ı: cc [options ] soubor ... • nejd˚uleˇzitˇejˇs´ıpˇrep´ınaˇce: -o soubor jm´enov´ysledn´ehosouboru -c pouze pˇreklad(nelinkovat) -E pouze preprocesor (nepˇrekl´adat) -l slinkuj s pˇr´ısluˇsnou knihovnou -Ljm´eno pˇridejadres´aˇrpro hled´an´ıknihoven z -l -Olevel nastaven´ı´urovnˇeoptimalizace -g pˇreklads ladic´ımiinformacemi -Djm´eno definuj makro pro preprocesor -Iadres´aˇr um´ıstˇen´ı #include soubor˚u

• -l/-L jsou pˇrep´ınaˇcelinker editoru, tj. kompil´atorpˇr´ısluˇsn´einformace pˇred´a, ale jsou pouˇz´ıv´any tak ˇcasto,ˇzejsou vloˇzeny i do tohoto slajdu. • kompil´atora 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ˇrebanastudovat dokumentaci konkr´etn´ıhoproduktu.

27 Pˇreddefinovan´amakra

__FILE__, __LINE__, __DATE__, __TIME__, __cplusplus, apod. jsou standardn´ımakra kompil´atoruC/C++ unix vˇzdydefinov´anov Unixu mips, i386, sparc hardwarov´aarchitektura linux, sgi, sun, bsd klon operaˇcn´ıhosyst´emu _POSIX_SOURCE, _XOPEN_SOURCE pˇrekladpodle pˇr´ısluˇsn´enormy pro pˇrekladpodle urˇcit´enormy by pˇredprvn´ım #include mˇelb´yt ˇr´adeks definic´ın´asleduj´ıc´ıhomakra. Pak naˇctˇete unistd.h.

UNIX 98 #define _XOPEN_SOURCE 500 SUSv3 #define _XOPEN_SOURCE 600 SUSv4 #define _XOPEN_SOURCE 700 POSIX1990 #define _POSIX_SOURCE

28 • funguje to tak, ˇzepomoc´ı 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ˇzdypo nastaven´ı maker nainkludovat unistd.h a pouˇz´ıtspr´avn´ypˇrekladaˇc. Napˇr´ıkladse pokus´ımepˇreloˇzitpro- gram basic-utils/standards.c , kter´yvyˇzaduje SUSv3, na syst´emu pod- poruj´ıc´ımSUSv3 (Solaris 10), ale pˇrekladaˇcem,kter´ypodporuje pouze SUSv2 (SUSv3 pˇrekladaˇcje c99). Pozor, ˇzedefaultn´ı chov´an´ı vaˇsehopˇrekladaˇce m˚uˇzeb´ytklidnˇepr´avˇeto z c89.

$ cat standards.c #define _XOPEN_SOURCE 600 /* you must #include at least one header !!! */ #include int main(void) { return (0); } $ c89 basic-utils/standards.c "/usr/include/sys/feature_tests.h", line 336: #error: "Compiler or options invalid; UNIX 03 and POSIX.1-2001 applications require the use of c99" cc: acomp failed for standards.c

• zdroj maker pro standard tedy m˚uˇzeb´ytjiˇzna stranˇe 14 zmiˇnovan´yhlaviˇc- kov´ysoubor feature tests.h na Solarisu. • v dokumentaci konkr´etn´ıhokompil´atoruje moˇzn´enaj´ıt,kter´adalˇs´ımakra se pouˇz´ıvaj´ı.Mnoˇzstv´ımaker je definov´anotak´ev syst´emov´ych hlaviˇckov´ych souborech. • POSIX.1 v sobˇezahrnuje ANSI C; tedy C89, ne C99 (o C standardech v´ıce na stranˇe 16).

• co se t´yˇcemaker k jednotliv´ym standard˚um,velmi dobr´aje kapitola 1.5 v [Rochkind]. Viz tak´e basic-tools/suvreq.c .

int main(void) { #ifdef unix printf("yeah\n"); #else printf("grr\n"); #endif return (0); }

• pˇr´ıkladna pouˇzit´ı LINE viz basic-tools/main LINE .c

29 Link editor (linker)

• Vol´an´ı: ld [options ] soubor ... cc [options ] soubor ... • Nejd˚uleˇzitˇejˇs´ıpˇrep´ınaˇce: -o soubor jm´enov´ysledn´ehosouboru (default a.out) -llib linkuj s knihovnou liblib.so nebo liblib.a -Lpath cesta pro knihovny (-llib ) -shared vytvoˇritsd´ılenouknihovnu -non shared vytvoˇritstatick´yprogram

• linker je program, kter´yvezme typicky v´ıceobjekt˚uvygenerovan´ych pˇrekla- daˇcema vytvoˇr´ız nich bin´arn´ıprogram, knihovnu nebo dalˇs´ıobjekt vhodn´y pro dalˇs´ıf´azi linkov´an´ı. • pozor na to, ˇzena r˚uzn´ych syst´emech se nˇekter´epˇrep´ınaˇcemohou liˇsit, napˇr´ıklad ld na Solarisu nezn´apˇrep´ınaˇce -shared a -non shared, je nutn´e pouˇz´ıtjin´e.

• existuje pˇrep´ınaˇc -R, kter´yumoˇzˇnujespecifikovat cestu pro hled´an´ıknihoven za bˇehu (runtime). Tato cesta se m˚uˇzeliˇsitod cesty specifikovan´epˇrep´ınaˇcem -L. • u mal´ych program˚u(v jednom souboru) lze prov´estpˇreklad a linkov´an´ı jedn´ımpˇr´ıkazem cc. U vˇetˇs´ıch program˚uskl´adaj´ıc´ıch se z mnoha zdrojov´ych soubor˚ua knihoven se obvykle oddˇelujepˇreklada linkov´an´ıa cel´yproces je ˇr´ızenutilitou make (strana 31).

30 R´ızen´ıpˇrekladuaˇ 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ˇzita slinkovat jedn´ımvol´an´ımkompil´atoru,nebo definovat postup pˇrekladua linkov´an´ıpomoc´ıshellov´ehoskriptu. D˚uvodem pro pouˇzit´ı make je to, ˇzevyhodnocuje z´avislostimezi soubory a po zmˇenˇe nˇekter´ehozdrojov´ehosouboru pˇrekl´ad´ajenom to, co na nˇemz´avis´ı. Cast´yˇ zp˚usobpˇrekladusoftwaru po aplikov´an´ızmˇenzp˚usobem “make clean; make all” je v situaci, kdy cel´ypˇrekladtrv´aminuty (des´ıtkyminut, hodiny. . . ), trochu nevhodn´y– pr´avˇeproto je d˚uleˇzit´em´ıtdobˇrenapsan´y Makefile. • ˇr´adek“prog : main.o util.o” definuje, ˇzese m´anejprve rekurzivnˇezajistit existence a aktu´alnostsoubor˚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. To b´yv´a all, coˇzvˇetˇsinou podle unixov´ekonvence pˇreloˇz´ıvˇse,co se pˇreloˇzitm´a.N´asledujepak tˇreba spuˇstˇen´ı make s parametrem install apod. • make je samozˇrejmˇeuniverz´aln´ın´astroj, pouˇziteln´yi jinde neˇzu pˇreklad˚u zdrojov´ych k´od˚u

• pˇr´ıklad: basic-utils/Makefile01 . Pozor na to, ˇze pro nestandardn´ıjm´eno vstupn´ıhosouboru je nutn´epouˇz´ıtpˇrep´ınaˇc -f:“make -f Makefile01”.

31 Syntaxe vstupn´ıhosouboru (make)

• popis z´avislost´ıc´ıle: targets :[files ] • prov´adˇen´epˇr´ıkazy: command • koment´aˇr: #comment • pokraˇcovac´ıˇr´adek: line-begin \ line-continuation

• Pozor na to, ˇzeˇr´adeks pˇr´ıkazem zaˇc´ın´atabul´atorem,nikoliv me- zerami. Kaˇzd´ypˇr´ıkazov´yˇr´adekse prov´ad´ısamostatn´ymshellem, pokud je potˇrebaprov´estv´ıceˇr´adk˚upomoc´ıjednoho shellu, mus´ıse vˇsechny aˇzna po- sledn´ıukonˇcitbackslashem (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ˇensamostatn´ymshellem. D´alesi vˇsimnˇete,ˇzepokud m´atepˇr´ıkaz na v´ıceˇr´adk˚u,mus´ıtekaˇzd´yˇr´adekukonˇcitzpˇetn´ymlom´ıtkem.

$ cat basic-utils/Makefile02 all: @echo $$$$ @echo $$$$ @if true; then \ echo $$$$; \ echo $$$$; \ fi $ make -f Makefile02 5513 5514 5515 5515

• co se t´yk´apouˇzit´ızpˇetn´eholom´ıtka, tak to funguje jako oddˇelovaˇcslov, a make m´ıstonˇejvloˇz´ımezeru. Pˇr´ıklad: basic-utils/Makefile07 . • zdvojen´ım $ se potlaˇc´ıspeci´aln´ıv´yznamdolaru (viz n´asleduj´ıc´ıslajd)

32 • znak @ na zaˇc´atkuˇr´adkupotlaˇc´ıjeho v´ypis– make jinak standardnˇevypisuje nejdˇr´ıve to, co bude vykon´avat. • vyps´an´ıvˇsech pˇrikaz˚ukter´ebude make prov´adˇetbez toho aby je skuteˇcnˇe provedl lze dos´ahnoutpouˇzit´ımpˇrep´ınaˇce -n. • znak - na zaˇc´atkuˇr´adkuzp˚usob´ıignorov´an´ınenulov´en´avratov´ehodnoty; jinak make vˇzdyv takov´esituaci zahl´as´ıchyby a okamˇzitˇeskonˇc´ı.Pˇr´ıklad: basic-utils/Makefile04 . • 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´anov´ıcekr´at,plat´ıjeho posledn´ıdefinice, viz pˇr´ıklad basic-utils/Makefile03 .

• makra nen´ımoˇzn´edefinovat rekurzivnˇe,viz basic-utils/Makefile05 :

$ cat basic-utils/Makefile05 M=value1 M=$(M) value2 all:

33 echo $(M) $ make -f Makefile05 Variable M is recursive.

• ˇcastose 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´ytjednoduch´e,proto existuj´ıprojekty jako je napˇr.GNU automake. Pro jed- noduch´ypodm´ıneˇcn´ypˇrekladv z´avislostina syst´emu a kde se daj´ıoˇcek´avat r˚uzn´everze pˇr´ıkazu make, je moˇzn´epouˇz´ıtnapˇr´ıkladn´asleduj´ıc´ık´od,kter´y mi fungoval na vˇsech v nˇemzm´ınˇen´ych syst´emech (znak ‘ je zpˇetn´yapostrof, a ’ je norm´aln´ıapostrof):

CFLAGS=‘x=\‘\‘; \ 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´epouˇz´ıt programy typu autoconf nebo automake. Nˇekter´e make implementace maj´ı pˇr´ımo direk- tivy pro podm´ınˇen´ezpracov´an´ıvstupn´ıhosouboru, napˇr´ıkladmake na BSD. Pˇr´ıklad: basic-utils/Makefile08.bsd . • pˇrep´ınaˇcem -e m˚uˇzeme make donutit, aby ignoroval nastaven´ıpromˇenn´ych ve vstupn´ımsouboru v pˇr´ıpadˇe,ˇzeje definov´anapromˇenn´aprostˇred´ıstejn´eho jm´ena.Norm´alnˇe make pˇreb´ır´aaktu´aln´ınastaven´ıpromˇenn´ych prostˇred´ıjen v pˇr´ıpadˇe,ˇzedan´epromˇenn´enejsou nastaven´eve vstupn´ımsouboru. Pˇr´ıklad: basic-utils/Makefile06 . • make je velmi siln´yn´astroj, staˇc´ıse pod´ıvat do syst´emov´ych Makefile sou- bor˚ujak´ehokoli unix-like syst´emu (najdˇetesi na Wikipedii, co to znamen´a “unix-like”, pokud to nev´ıte).Typickou spoleˇcnouvlastnost´ıje to, ˇzeneexis- tuje dokumentace, jak je dan´ymakefile framework postaven.

34 Dynamick´ylinker (loader)

• pˇrekladvyˇzadujevˇsechny potˇrebn´edynamick´eknihovny pro kontrolu dosaˇzitelnostipouˇzit´ych symbol˚u • sestaven´ıkompletn´ıhoprogramu v pamˇetise ale provede aˇzpˇrispuˇstˇen´ı. To je ´ukol pro dynamick´ylinker (run-time linker, loader) • seznam dynamick´ych knihoven zjist´ıze sekce .dynamic • syst´emm´anastaveno nˇekolik cest, kde se automaticky tyto knihovny hledaj´ı • v sekci .dynamic je moˇzn´edalˇs´ıcesty ke knihovn´ampˇridat pomoc´ıtag˚u RUNPATH/RPATH • nalezen´eknihovny se pˇripoj´ıdo pamˇet’ov´ehoprocesu pomoc´ı vol´an´ı mmap() (bude pozdˇeji)

• proces spuˇstˇen´ıdynamicky slinkovan´ehoprogramu prob´ıh´atakto:

– kernel ve vol´an´ı exec namapuje program do pamˇetia zjist´ı,jak´ydyna- mick´ylinker se m´apouˇz´ıt(viz d´ale) – kernel namapuje linker do pamˇet’ov´ehoprostoru spouˇstˇen´eho programu a pak linkeru pˇred´akontrolu. Linker je program s´amo sobˇe– na Solarisu je ho moˇzn´enorm´alnˇespustit (m´atedy funkci main) a jako parametr mu d´atjm´enoprogramu. Moˇznostspouˇstˇetdynamick´ylinker z pˇr´ıkazov´eho ˇr´adkuje ale hlavnˇepro experimentovan´ıs linkerem pˇrijeho v´yvoji. – linker z hlaviˇckyprogramu zjist´ı, jak´edynamick´eknihovny program pouˇz´ıv´a,namapuje je do pamˇetia zavol´ajejich inicializaˇcn´ıfunkce, po- kud existuj´ı.Mapuj´ıse vˇsechny nalezen´ez´avislostikter´enejsou nasta- ven´ejako lazy (strana 144), rekurz´ıvnˇeprohled´av´an´ımdo ˇs´ıˇrky. V tomto poˇrad´ıse pak tak´eobjekty prohled´avaj´ıpˇrihled´an´ıjednotliv´ych sym- bol˚u. – linker programu pˇred´aˇr´ızen´ı(tj. zavol´afunkci main) – proces m˚uˇzei za bˇehu d´alevyuˇz´ıvat dynamick´ylinker pomoc´ıvol´an´ı dlopen a spol.; k tomu se dostaneme na stranˇe 144

• je potˇrebasi uvˇedomit,ˇzedynamick´ylinker zde nepracuje jako samostatn´y proces pˇrestoˇzem´asvoji vlastn´ı main funkci, jeho k´odse pouˇz´ıv´av r´amci pamˇet’ov´ehoprostoru procesu; program, linker a knihovny dohromady tvoˇr´ıjeden proces.

35 • n´asleduj´ıc´ıpˇr´ıkazy a pˇr´ıkladyse t´ykaj´ıSolarisu. Pokud to nebude fun- govat na jin´ych syst´emech, tak maj´ıekvivaletn´ın´astroje s podobnou funkci- onalitou.

– seznam sekc´ıse zjist´ıpomoc´ı elfdump -c (GNU m´apˇr´ıkazy objdump a readelf). O programov´ych sekc´ıch bude v´ıcena stranˇe 133. – to, jak´ydynamick´ylinker se pouˇzije,kernel zjist´ı ze sekce .interp, viz ”elfdump -i” a “ld -I”. To znamen´a,ˇzesi m˚uˇzetenapsat vlastn´ı linker a pomoc´ı -I pro ld ho pak nastavit jako dynamick´ylinker pro v´aˇsprogram. – dynamick´asekce se vyp´ıˇsepomoc´ı elfdump -d, dynamick´eknihovny jsou oznaˇcen´etagem NEEDED – z´avislostina dynamick´ych knihovn´ach je moˇzn´epohodlnˇezjistit pomoc´ı pˇr´ıkazu ldd (Solaris, Linux, BSD), kter´yzjist´ıkonkr´etn´ıcesty ke kni- hovn´am.Tento pˇr´ıkaz ˇreˇs´ız´avislostirekurz´ıvnˇea uvid´ıtetedy i nepˇr´ım´e z´avislosti- tj. takov´eknihovny, kter´ejsou pouˇzit´eknihovnami, kter´e pˇr´ısluˇsn´yprogram pouˇz´ıv´apˇr´ımo.Zjistit co je pˇresnˇez´avisl´ena ˇcemje moˇzn´epomoc´ıvolby -v. Na OS X je ekvivalentem ldd pˇr´ıkaz otool -L. – jak´eknihovny byly pˇrispuˇstˇen´ınakonec pouˇzity m˚uˇzeb´ytjin´eneˇzco uk´aˇzepˇr´ıkaz ldd, a to tˇrebad´ıkymechanismu LD PRELOAD. Na Solarisu proto existuje pˇr´ıkaz pldd, kter´ypomoc´ıˇc´ıslaprocesu uk´aˇzez´avislosti konkr´etn´ıhoprocesu. Pˇr´ıkladna LD PRELOAD: pouˇzijtejiˇzzm´ınˇen´y Ma- kefile01, a pˇreloˇzte basic-utils/preload.c takto: “cc -shared -o libpreload.so preload.c”. Pak spust’te program, kter´yzachyt´ı syst´emov´evol´an´ı close:“LD_PRELOAD=./libpreload.so ./a.out”. – vˇetˇsinu zde uveden´ych informac´ınaleznete v manu´alov´estr´ancepro dy- namick´ylinker v Solarisu, ld.so.1(1), a v´ıcepak v Linkers and Lib- raries Guide na docs.oracle.com. Na FreeBSD se dynamick´ylinker naz´yv´a ld-elf.so.1, v linuxov´ych distribuc´ıch vˇetˇsinou ld-linux.so.1, na IRIXu rld atd. – dynamick´ylinker se typicky d´akonfigurovat pomoc´ınastaven´ıpromˇen- n´ych, napˇr´ıkladsi zkuste na Solarisu spustit toto: LD_LIBRARY_PATH=/tmp LD_DEBUG=libs,detail date a pro zjiˇstˇen´ıvˇsech moˇznost´ıjak debugovat dynamick´ylinker pouˇzijte: LD_DEBUG=help date – pˇr´ıkladna to, kdy je potˇreba,aby linker hledal knihovny i jinde neˇzv de- faultn´ıch adres´aˇr´ıch (adres´aˇrespecifikovan´epromˇennou LD LIBRARY PA- TH se prohled´avaj´ıjako prvn´ı): $ 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 – Solaris m´avelmi zaj´ımav´ypˇr´ıkaz elfedit(1), pomoc´ıkter´ehom˚uˇzete editovat metadata ELF objektu, napˇr´ıkladpˇrepsatjm´enoz´avisl´ekni- hovny, zmˇenitnastaven´ı RUNPATH atd.

36 • Obecnˇeplat´ı,ˇzepouˇz´ıvat LD LIBRARY PATH k ovlivnˇen´ıbˇehu dynamick´eho linkeru pro nˇecojin´ehoneˇzladˇen´ı dynamick´ych knihoven pˇriv´yvoji nebo pˇresunech knihoven mezi adres´aˇrinen´ıdobr´yn´apad.Na internetu lze naj´ıt mnoˇzstv´ıˇcl´ank˚utypu ”why is LD LIBRARY PATH evil ?”apod., napˇr. http: //xahlee.org/UnixResource dir/ /ldpath.html. Tato promˇenn´aje typicky zneuˇz´ıvan´ave startovac´ıch skriptech program˚u, aby pˇredsunuly alternativn´ıseznam adres´aˇr˚ukde hledat dynamick´eknihovny na kter´ych program z´avis´ı. To vˇetˇsinouproto, ˇzebyl program nespr´avnˇe slinkov´ana dynamick´ylinker by podle informac´ı v ELFu nedok´azaljinak knihovny naj´ıt.Typick´ynechtˇen´yside effect je, ˇzeprogram d´alespust´ıjin´y program, kter´ypouˇz´ıv´aknihovnu stejn´ehojm´ena,ale ”d´ıky”tomu, ˇzese promˇenn´eprostˇred´ı dˇed´ı, tak dynamick´ylinker najde tuto knihovnu jako prvn´ıv ares´aˇrispecifikovan´empomoc´ı LD LIBRARY PATH. Tato knihovna m˚uˇze b´ytale jin´everze, neˇzten druh´yprogram oˇcek´av´a,a pak snadno m˚uˇzedoj´ıtk nˇeˇcemu, co se vˇetˇsinounaz´yv´a”nedefinovan´echov´an´ı”(vizpˇr´ıkladu dalˇs´ıho slide o ABI).

API versus ABI

API – Application Programming Interface • rozhran´ıpouˇzit´epouze ve zdrojov´emk´odu • rozhran´ı zdroj´aku v˚uˇcisyst´emu, knihovnˇeˇcivlastn´ımu k´odu, tj. napˇr. exit(1), printf("hello\n") nebo my function(1, 2) • . . . aby se stejn´y zdrojov´yk´od mohl pˇreloˇzitna vˇsech syst´emech podporuj´ıc´ıdan´eAPI ABI – Application Binary Interface • low-level rozhran´ı aplikace v˚uˇcisyst´emu, knihovnˇeˇcijin´eˇc´asti sama sebe • . . . aby se objektov´ymodul mohl pouˇz´ıtvˇsudetam, kde je podporov´anostejn´eABI

• Pˇr´ıklademAPI je tˇrebaAPI 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´ıslasyst´emov´ych vol´an´ı,jak se syst´emov´evol´an´ı provede ˇciform´atobjektov´ehomodulu a pˇrij´ıman´ych argument˚u,viz pˇr´ıkladdole. • API knihovny pak definuje mimo jin´emnoˇzinu vol´an´ıkter´ajsou knihovnou definov´ana,jejich parametry a typy tˇechto parametr˚u.

37 • n´asledn´auk´azka je pˇr´ıkladna to, kdy v´yvoj´aˇrzmˇen´ıvelikost argument˚uv bajtech (tj. zmˇen´ıABI knihovny), a nahrad´ınovou verz´ıtu starou. Vˇsimnˇete si, ˇzedynamick´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ˇenav API a probl´emby se odstranil, kdybychom main.c znovu pˇreloˇzilise zmˇenˇen´ymˇr´adkem deklarace funkce add. To je ale ˇcastoprobl´em (pˇrekl´adejtecel´ysyst´emjen kv˚ulitomu), proto je tak d˚uleˇzit´edodrˇzovat zpˇetnoukompatibilitu v ABI u knihoven. V´ysledekn´asleduj´ıc´ıhopˇrekladu knihovny, programu a jeho spuˇstˇen´ıje jak bychom oˇcek´avali (pouˇzit cc ze SunStudio, pro gcc pouˇzijtem´ısto -G volbu -shared; novˇejˇs´ı gcc nav´ıcneznaj´ı -R a je m´ıstotoho nutn´epouˇz´ıt -Xlinker -R .:

$ cat main.c int my_add(int a, int b);

int main(void) { printf("%d\n", my_add(1, 2)); 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 3

Nyn´ıale pˇriˇsladalˇs´ıverze knihovny se stejn´ymjm´enem, a ve funkci my add nastala zmˇena v typu argument˚u,kde m´ısto4-bajtov´ehointegeru se pouˇzije 64-bitov´yceloˇc´ıseln´ytyp. Program ale o niˇcemnev´ı,nech´ase spustit a vr´at´ı chybnou hodnotu:

$ cat add2.c int64_t my_add(int64_t a, int64_t b) { return (a + b); }

$ cc -G -o libadd.so add2.c $ ./a.out -1077941135

• pˇr´ıklad: lib-abi/abi-main.c (koment´aˇrv souboru napov´ıjak pouˇz´ıtos- tatn´ısoubory ve stejn´emadres´aˇri)

38 • zde pak pˇrich´az´ıke slovu verzov´an´ıknihoven, tj. je nutn´e“nˇeco”zmˇenittak, aby po instalaci nov´eknihovny neˇsloprogram spustit bez jeho rekompilace.

• bin´arn´ınekompatibilita je napˇr´ıkladprobl´emu OpenSSL. Vˇetve 0.9.x a 0.9.y nejsou ABI kompatibiln´ı.Konkr´etnˇeverze 0.9.7 a 0.9.8, v roce 2009 st´aleobˇe pouˇz´ıvan´e.Verze rozliˇsen´ep´ısmeny, tj. napˇr´ıklad0.9.8a a 0.9.8g, jsou ABI kompatibiln´ı.Nˇekter´esyst´emy st´alepouˇz´ıvaj´ıpouze 0.9.7 (FreeBSD 6.x, So- laris 10), jin´ejen 0.9.8 (Solaris 11 Express), dalˇs´ıintegruj´ıobˇevˇetve (r˚uzn´e Linuxov´edistribuce). Probl´emje, m´ate-linapˇr´ıkladprogram pro Solaris 10 pouˇz´ıvaj´ıc´ı libcrypto.so knihovnu, kter´ychcete pouˇz´ıvat i na Solaris 11 Ex- press (to je jinak d´ıkyzpˇetn´ebin´arn´ıkompatibilitˇestriktnˇedodrˇzovan´emezi ”major”verzemi Solarisu moˇzn´e- napˇr.program kter´ybˇeˇzel na Solarisu 2.6 z roku 1997 m˚uˇzebˇeˇzetna Solarisu 10 z roku 2009 bez nutnosti rekompilace - to se t´yk´asyst´emu a knihoven s n´ımdod´avan´ych). Jedin´espr´avn´ereˇsen´ıje zkompilovat pro nov´ysyst´em,pˇr´ıpadnˇemanu´alnˇezkop´ırovat potˇrebn´everze knihoven, coˇzale zdaleka nen´ıide´aln´ı– program nebude fungovat s novˇena- instalovan´ymsyst´emem,ale nikdo najednou nev´ı,proˇcto funguje na stejn´em syst´emu vedle, a kdyˇzse to zjist´ıtak je opˇetpotˇrebamanu´aln´ız´asah,a po- chybuji o tom, ˇzeautor “ˇreˇsen´ı”bude instalovat opraven´everze pˇriv´yskytu bezpeˇcnostn´ıch chyb. Nekompatibilita 0.9.x verz´ıje d˚uvodem, proˇcje v dy- namick´esekci knihovny i jej´ıcel´eˇc´ıslo(bez p´ısmen,ta jak jiˇzv´ımenejsou pro ABI kompatibilitu u OpenSSL d˚uleˇzit´a),a d´ıkytomu je pak toto ˇc´ıslo uvedeno i v kaˇzd´emprogramu proti knihovnˇeslinkovan´emu:

$ elfdump -d /usr/sfw/lib/libcrypto.so.0.9.8 | grep SONAME [7] SONAME 0x1 libcrypto.so.0.9.8

$ elfdump -d /usr/bin/ssh | grep NEEDED [1] NEEDED 0x3c99 libsocket.so.1 [3] NEEDED 0x3cb1 libnsl.so.1 [5] NEEDED 0x3cc6 libz.so.1 [7] NEEDED 0x3d12 libcrypto.so.0.9.8 [9] NEEDED 0x3cd9 libgss.so.1 [10] NEEDED 0x3cfe libc.so.1

– pˇr´ıˇcinouzpˇetn´enekompatibility OpenSSL verz´ıje to, ˇzez historick´ych d˚uvod˚ujsou nˇekter´epouˇz´ıvan´estruktury v hlaviˇckov´ych souborech. Tyto struktury je ale nˇekdynutn´erozˇs´ıˇrit, napˇr´ıkladpˇriv´yvoji nov´e funkcionality. T´ımnastane situace, ˇzeprogram pˇreloˇzen´ys verz´ı0.9.7 by pˇredalnovˇejˇs´ıknihovnˇe“menˇs´ı”strukturu, respektive nov´aknihovna by pˇristupovala ve star´estruktuˇrena poloˇzky, kter´eneexistuj´ı– a tedy by pˇristupovala k pamˇeti,kter´aprogramu nebyla pˇridˇelena.To m˚uˇze zp˚usobitp´adprogramu (pˇr´ıstupna nenamapovanou str´anku),m˚uˇzeto fungovat d´ale(v dan´epamˇetije to, co se tam typicky oˇcek´av´a,napˇr´ıklad nula), nebo se to zaˇcnechovat “podivnˇe”(v pamˇetibylo nˇeco,co v dan´e situaci oˇcek´avan´enebylo). Probl´emv OpenSSL je, ˇzenyn´ıjiˇznen´ıtech- nicky jednoduch´ez tˇechto struktur udˇelatintern´ıa navenek pracovat jen s transparentn´ımireferencemi objektov´ympˇr´ıstupem, coˇzby umoˇznilo dˇelatlibovoln´ezmˇeny ve struktur´ach, aniˇzby to program ovlivnilo. – bˇeˇznˇevidˇen´eˇreˇsen´ı zp˚usoben´eneznalost´ı vˇecije vytvoˇritsymbolick´y link, napˇr´ıkladna Solarisu 11 udˇelat0.9.7 symlink na existuj´ıc´ıknihovnu verze 0.9.8. Cast´yv´ysledekjeˇ pak p´adprogramu a ´udivautora symlinku. Nˇekdyto naopak funguje, protoˇzeprogram n´ahodou nepouˇz´ıv´apˇr´ısluˇsn´e

39 struktury, a to je jasn´ymd˚ukazem pro akt´era,ˇzeˇreˇsen´ımus´ıb´ytspr´avn´e. M˚uˇzese ale st´at,ˇzeprogram struktury nepouˇz´ıv´apˇrikonkr´etn´ımpro- veden´emtestu, ale zaˇcnedˇelatprobl´emy aˇzpˇriˇziv´emnasazen´ı.Tady je jedin´arada – pokud si opravdu nejste jisti ˇzev´ıte,co dˇel´atea nejste si jist´ısvoji detailn´ıznalost´ık´oduprogramu i knihoven, vyhnˇetese tomu. Nebo riskujte, ale jiˇzv´ıtejak to m˚uˇzeskonˇcit. – zd´anlivˇejednoduch´eˇreˇsen´ıdod´avat v´ıceverz´ıOpenSSL s jedn´ımsyst´e- mem pˇrin´aˇs´ızase jin´eprobl´emy – obt´ıˇznˇejˇs´ıv´yvoj syst´emu, obt´ıˇznˇejˇs´ı spr´avusyst´emu (pˇriv´yskytubezpeˇcnostn´ıchyby je ˇcastonutn´epatcho- vat vˇsechny instalovan´everze), probl´emy s nepˇr´ım´ymiz´avislostmiobsa- huj´ıc´ıv´ıceverz´ıdan´eknihovny apod. – upgrade verze OpenSSL v existuj´ıc´ımsyst´emu je tak´evˇec,kter´eje dobr´e se vyhnout, respektive toto tˇeˇzko vyˇreˇs´ıtevyd´an´ımpatche pro existuj´ıc´ı syst´emy – uvaˇzteˇzez´akazn´ıkpouˇz´ıv´asv´enebo j´ımkoupen´eprogramy, kter´ez´avis´ına existuj´ıc´ıverzi. A tu byste mu najednou upgradovali na verzi vyˇsˇs´ı,ABI nekompatibiln´ı. – typick´ympˇr´ıkladem,kdy se pouˇz´ıv´atransparentn´ıtyp jako reference, coˇzumoˇzˇnujedalˇs´ırozˇsiˇrov´an´ıpod n´ıleˇz´ıc´ıstruktury bez rizika v´yˇse uveden´ych probl´em˚u,je typ POSIX vl´aken. Struktura typu pthread t (strana 195) je intern´ız´aleˇzitost´ıknihovny. Typicky je to integer, ale to by program´atoranemˇelov˚ubec zaj´ımat.Samozˇrejmˇesouborov´ydeskrip- tor ˇciˇc´ısloprocesu jsou podobn´epˇr´ıpady, ale na pˇr´ıkladuvl´aken je to l´epe vidˇet.

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´ımdo 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´ı

40 b´ytprogram pˇreloˇzens ladic´ımiinformacemi (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´ıtnapˇr.na Solarisu, avˇsakna Linuxu a FreeBSD defaultnˇe nen´ı. • pro debugging se zdrojov´ymik´odynestaˇc´ıpouˇz´ıtvolbu -g, je z´aroveˇnnutn´e m´ıti zdroj´akya objektov´emoduly tam, kde byly pˇripˇrekladu.To je typicky bˇeˇzn´asituace, protoˇzelad´ıtena stroji, kde z´aroveˇni vyv´ıj´ıte.Pokud tomu tak nen´ı,je nutn´esi zdroj´akya objektov´emoduly zajistit, pokud k nim vede jin´acesta, lze pouˇz´ıtdbx pˇr´ıkaz pathmap. • gdb-kompatibiln´ı m´odse spust´ı pˇres gdb on. Pokud v´aszaj´ım´a,jak´ym´a dbx ekvivalentn´ıpˇr´ıkaz ke konkr´etn´ımu gdb pˇr´ıkazu, pom˚uˇzev´am help FAQ; hned prvn´ıot´azka je “A.1 Gdb does ; how do I do it in dbx?” • pokud nepouˇzijetepˇrep´ınaˇc-g, bude v´amdbx na Solarisu st´aleplatn´y,protoˇze zobraz´ıargumenty funkc´ı. U BSD syst´em˚ua linuxov´ych distribuc´ı-g pouˇz´ıt mus´ıte,jinak v´amdebuggery moc nepomohou. Kdy je to na Solarisu platn´e i bez -g je v vidˇetv pˇr´ıkladu debug/dbx.c . Pˇrikompilaci s gcc a pouˇzit´ı gdb neuk´aˇzepˇr´ıkaz where parametry funkce crash() zat´ımcose Solaris Stu- dio kompilerem a debuggerem dbx se parametry funkce vyp´ıˇs´ı,takˇzeje vidˇet hodnota kter´ase pˇriˇrazovala.

• pˇr´ıklad: debug/coredump.c . Po pˇreloˇzen´ıa spuˇstˇen´ıprogram spadne a za- nech´acore dump.

$ cc coredump.c $ ./a.out Segmentation Fault (core dumped) $ dbx ./a.out core Reading a.out core file header read successfully Reading ld.so.1 Reading libc.so.1 program terminated by signal SEGV (no mapping at the fault address) 0x08050a05: bad_memory_access+0x0015: movb %al,0x00000000(%edx) (dbx) where =>[1] bad_memory_access(0x8047ae8, 0x8047a44, ... [2] main(0x1, 0x8047a50, 0x8047a58, 0x8047a0c), at 0x8050a1b

Vid´ıme,ve kter´efunkci to spadlo a je moˇzn´ese vypsat z´asobn´ık.Nevid´ıme ale pˇresnˇeˇr´adkuk´odu,kde nastal probl´em.Pro to je nutn´epˇreloˇzitpro- gram s lad´ıc´ımisymboly, tj. “cc -g coredump.c”. Z´ajemce o v´ıceinformac´ı o debugging pod unixem odkazuji na navazuj´ıc´ıpˇredn´aˇsku“Programov´an´ıv UNIXu II.” (NSWI138).

$ cc -g coredump.c $ dbx ./a.out core Reading a.out core file header read successfully Reading ld.so.1

41 Reading libc.so.1 program terminated by signal SEGV (no mapping at the fault address) Current function is bad_memory_access 8 x[0] = ’\0’; (dbx)

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´ımdo funkce) break condition nastaven´ıbreakpointu help [name ] n´apovˇeda quit ukonˇcen´ıdebuggeru

• GNU obdoba dbx. M´odkompatibiln´ıs dbx spust´ıtepˇres -dbx. • na r˚uzn´ych platform´ach existuj´ıi debuggery s grafick´ymrozhran´ım,napˇr. workshop (Solaris), cvd (IRIX), xxgdb (GNU), ddd (GNU). Castoˇ funguj´ı jako nadstavby nad dbx, gdb. • #include int main(void) { printf("hello, world\n"); return (0); } $ cc -g main.c $ gdb -q a.out (gdb) break main Breakpoint 1 at 0x8048548: file main.c, line 4. (gdb) run Starting program: /share/home/jp/src/gdb/a.out

Breakpoint 1, main () at main.c:4 4 printf("hello, world\n");

42 (gdb) next hello, world 5 return (0); (gdb) c Continuing. Program exited normally. (gdb) q • debuggery jsou v´yborn´ymipomocn´ıkypokud v´aˇsprogram konˇc´ına chyby typu “segmentation error” – tj. kdyˇzzkus´ıtenekorektnˇepˇristoupitdo pamˇeti, napˇr´ıkladtam kde nem´ateco dˇelat.Kdyˇzpˇripˇrekladupouˇzijeteoption -g, uk´aˇzev´ampak 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ˇzitna Solarisu pˇrekladaˇcem cc a spustit):

$ cat -n main.c 1 int 2 main(void) 3 { 4 char *c = "hey world"; 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’;

43 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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

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´acese znaky string.h . . . pr´aces ˇretˇezci time.h . . . pr´aces datem a ˇcasem math.h . . . matematick´efunkce setjmp.h . . . dlouh´eskoky assert.h . . . ladic´ıfunkce stdarg.h . . . pr´aces promˇenn´ympoˇctemparametr˚u limits.h . . . implementaˇcnˇez´avisl´ekonstanty signal.h . . . oˇsetˇren´ısign´al˚u

44 • 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.

• tyto hlaviˇckov´esoubory nejsou specifick´epro UNIX. Jsou souˇc´ast´ı standardu ANSI C, kter´yjak jiˇzv´ıme(strana 16), je zahrnut v POSIX.1. Je ale d˚uleˇzit´esi uvˇedomit,ˇzetyto hlaviˇckov´esoubory mus´ıpodporovat kaˇzd´ysyst´em,kter´ypodporuje ANSI C, at’ jiˇz podporuje POSIX.1 nebo ne.

• pˇr´ısluˇsn´yhlaviˇckov´ysoubor pro konkr´etn´ıfunkci najdete v manu´alov´estr´ance dan´efunkce, toto je zaˇc´atekmanu´alov´estr´ankyna Solarisu pro memcpy:

Standard C Library Functions memory(3C)

NAME memory, memccpy, memchr, memcmp, memcpy, memmove, memset - memory operations

SYNOPSIS #include ......

• jednotliv´amakra obsaˇzen´av tˇechto souborech vˇetˇsinounejsou vysvˇetlena, v´yznamjednotliv´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ˇehemkompilace odstranit pomoc´ımakra NDEBUG. Pˇr´ıklad: assert/assert.c .

cat assert.c #include

int main(void) { assert(1 == 0); return (13); } $ cc assert.c $ ./a.out Assertion failed: 1 == 0, file assert.c, line 6 Abort (core dumped) $ cc -DNDEBUG assert.c $ ./a.out $ echo $? 13

45 Standardn´ıhlaviˇckov´esoubory (2)

unistd.h . . . symbolick´ekonstanty, typy a z´akladn´ıfunkce sys/types.h . . . datov´etypy 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´aces regul´arn´ımiv´yrazy

• tyto headery uˇzpatˇr´ıdo UNIXu.

• zaj´ımav´em˚uˇzeb´yt pod´ıvat se do sys/types.h

46 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´ymiadresami 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´ı.

47 Funkce main()

• pˇrispuˇstˇen´ıprogramu je pˇred´anoˇr´ızen´ıfunkci main(). • int main (int argc, char *argv []); – argc . . . poˇcetargument˚upˇr´ıkazov´eˇr´adky – argv . . . pole argument˚u ∗ podle konvence je argv[0] jm´enoprogramu (bez cesty) ∗ posledn´ıprvek je argv[argc] == NULL – n´avratz 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ˇcetargument˚una pˇr´ıkazov´emˇr´adku (vˇcetnˇeargumentu 0 – jm´enaprogramu) a druh´yparametr (typu char**) je pole ukazatel˚una tyto ˇretˇezce. Za posledn´ımˇretˇezcemje jeˇstˇeukonˇcovac´ı NULL pointer – pozor na to, ˇzeto je nˇecojin´ehoneˇzpr´azdn´yˇretˇezec. • argv[0] nˇekdyb´yv´ad˚uleˇzit´ym zdrojem pˇridan´einformace. Na Solarisu jsou napˇr´ıkladpˇr´ıkazy cp, mv a ln nalinkovan´ena stejn´ysoubor. Hodnota argv[0] pak urˇcuje,jakou funkci vlastnˇeproces m´a.Jin´ypˇr´ıklad– pokud m´ashell prvn´ıznak z argv[0] nastaven na “-”, znamen´ato, ˇzese m´achovat jako lo- gin shell (pod´ıvejte se tˇrebado manu´alov´estr´ankypro bash na sekci INVO- CATION, pokud nev´ıte,co to je login shell). Ve v´ypisuproces˚upak uvid´ıte “-bash”. Toto nen´ısouˇc´astUNIX specifikace pro sh, ale pouˇz´ıval to jiˇzBourne shell na UNIXu V7 (1979) a ostatn´ıshelly to pˇrevzaly.

• pˇrispuˇstˇen´ı programu pˇred´ak´oddynamick´eholinkeru ˇr´ızen´ı funkci main, viz strana 35. Staticky slinkovan´emu programu se ˇr´ızen´ıpˇred´apˇr´ımo.Ne- pˇr´ıtomnost main v programu zp˚usob´ıchybu pˇripˇrekladuna ´urovni linkeru. T´etofunkci se pˇred´ajm´enospuˇstˇen´ehoprogramu, argumenty z pˇr´ıkazov´e ˇr´adkya pˇr´ıpadnˇei promˇenn´eprostˇred´ı.Ukonˇcen´ıt´eto funkce znamen´akonec programu a n´avratov´ahodnota se pouˇzijejako k´odukonˇcen´ıprogramu pro OS. Jinou moˇznost´ıukonˇcen´ıprogramu je pouˇzit´ıfunkce exit nebo _exit, kterou lze pouˇz´ıtkdykoliv, nejen ve funkci main. V C lze pouˇz´ıvat obˇemetody ukonˇcen´ıprogramu.

• pˇred´an´ıpromˇenn´ych prostˇred´ıtˇret´ımparametrem typu char** nen´ısouˇc´ast´ı normativn´ıˇc´astiC standardu, pouze informativn´ı.Pˇrekladaˇceto ale typicky

48 podporuj´ı.Varianta main s promˇenn´ymiprostˇred´ıpak vypad´atakto: int main(int argc, char *argv [], char *envp []);

• n´avratov´ytyp funkce main by mˇelb´ytvˇzdy int; pˇrekladaˇcsi jinak bude stˇeˇzovat. Z t´etohodnoty se ale pouˇzijepouze nejniˇzˇs´ıch 8 bit˚u, a je to nez´aporn´eˇc´ıslo. Pozor na to, ˇzena rozd´ıl od konvence jazyka C n´avratov´ahodnota 0 m´av shellu v´yznamtrue (´uspˇech) a nenula v´yznam false (ne´uspˇech). Typick´akonstrukce v shellu vypad´atakto:

if ! prog; then echo "failure" else echo "success" fi

Pˇr´ıklad: main/return-256.c . • nepouˇz´ıvejte proto ve funkci main return (-1) a nikde pak ani exit(-1), z toho vznikne n´avratov´ahodnota 255 a k´odje matouc´ı.Je v˚ubec velmi vhodn´e pouˇz´ıvat pouze 0 a 1, pokud nen´ız´asadn´ıd˚uvod pro jin´ehodnoty, tˇrebaten ˇzejich potˇrebujetev´ıce– m˚uˇzetese pod´ıvat napˇr´ıkladna manu´alovou str´anku pro passwd na Solarisu, sekce EXIT STATUS. Pˇr´ıklad: main/return-negative-1.c .

• rozd´ılmezi funkcemi exit a _exit je v tom, ˇze exit pˇredukonˇcen´ımpro- gramu jeˇstˇevypr´azdn´ı(pomoc´ıknihovn´ıfunkce fflush) a zavˇrestreamy a vol´afunkce zaregistrovan´epomoc´ı atexit. V z´avislostina syst´emu to mohou b´yti dalˇs´ıakce. Pro zaj´ımavost, napˇr´ıklad ve FreeBSD je exit syst´emov´evol´an´ı a exit knihovn´ı funkce, ale na Solarisu jsou obˇesyst´emov´ymivol´an´ımi. Pˇr´ıklad: exit/exit.c

• pˇr´ıklad: main/print-argv.c

49 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ˇezceve 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ˇrebapromˇennou znovu exportovat. Pˇr´ıkaz env v´amvyp´ıˇseaktu´aln´ıpromˇenn´eprostˇred´ı.Abyste pˇridalipromˇennou do prostˇred´ıspouˇstˇen´ehoprogramu staˇc´ıprov´estpˇriˇrazen´ı na pˇr´ıkazov´eˇr´adce,aniˇzbyste museli mˇenitprostˇred´ıvaˇsehoshellu:

$ date Sun Oct 7 13:13:58 PDT 2007 $ LC_TIME=fr date dimanche 7 octobre 2007 13 h 14 PDT

nedivte se, pokud to na vaˇsemsyst´emu takto fungovat nebude, v tom pˇr´ıpadˇe nem´ateinstalovan´ybal´ıks francouzskou lokalizac´ı(coˇzje pravdˇepodobn´e). • pˇrinahrazen´ıaktu´aln´ıhoobrazu procesu obrazem jin´ymse pˇred´av´a,pokud se neˇreknejinak, synovsk´ymproces˚umcel´epole environ automaticky. Je moˇzn´eve vol´an´ıpˇr´ısluˇsn´evarianty funkce exec pˇredatpole 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´ytv manu´alov´estr´ance.Typicky v sekci nazvan´e ENVIRONMENT nebo ENVIRONMENT VARIABLES

• man napˇr´ıkladpouˇz´ıv´a PAGER, vipw pak promˇennou EDITOR apod.

• pokud je envp tˇret´ımparametrem funkce main, tak je to stejn´ahodnota co je v ukazateli environ.

50 • pˇr´ıklad: main/print-env.c (vˇcetnˇepouˇzit´ı env pˇr´ıkazu zp˚usobem, kter´y vyˇcist´ızdˇedˇen´epromˇenn´eprostˇred´ı).

$ cc print-env.c $ env - XXX=yyy aaa=ABC ./a.out aaa=ABC XXX=yyy

Manipulace s promˇenn´ymiprostˇred´ı

• je moˇzn´epˇr´ımomˇenitpromˇennou environ, SUSv3 to ale nedoporuˇcuje

• 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´ıteproto pouˇz´ıvat retˇezcev automatick´ych pro- mˇenn´ych, toto ˇreˇs´ı setenv, kter´yhodnotu promˇenn´ezkop´ıruje.Viz pˇr´ıklad main/putenv.c .

• d˚uleˇzit´eje zapamatovat si, ˇzesynovsk´yproces zdˇed´ıv okamˇzikusv´ehovzniku od rodiˇcevˇ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´ıhopotomka.

• dalˇs´ırozd´ılmezi putenv a setenv je ten, ˇzev setenv mohu definovat, zda existuj´ıc´ıpromˇennouchci nebo nechci pˇrepsat. putenv vˇzdypˇrepisuje. • int main(void) { printf("%s\n", getenv("USER"));

51 return (0); } $ ./a.out jp • jelikoˇzpromˇenn´a environ je obyˇcejn´epole ukazatel˚una ˇretˇezce, nen´ınebˇeˇzn´e narazit na k´od,kter´ys t´ımto polem pracuje pˇr´ımo.Pozor vˇsakna to, ˇzev takov´empˇr´ıpadˇepak jiˇznesm´ıtepouˇz´ıvat zde uveden´efunkce, jinak se m˚uˇzete dostat do probl´em˚us jejich konkr´etn´ıimplementac´ı.A hlavnˇe,nov´yk´odtakto nepiˇste,protoˇzenorma SUSv3 pˇr´ımoupr´acis t´ımto polem nedoporuˇcuje.

• pˇr´ıklad: main/getenv.c

• pozor na to, ˇzeje rozd´ıl mezi nastaven´ım hodnoty promˇenn´ena pr´azdn´y string a odmaz´an´ımpromˇenn´eze seznamu promˇenn´ych (pomoc´ı unsetenv).

Zpracov´an´ıargument˚uprogramu

• obvykl´yz´apisv shellu: program -pˇrep´ınaˇceargumenty • pˇrep´ınaˇcetvaru -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ˇcitdohromady: 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ˇzeb´ytd˚uleˇzit´ea je na aplikaci, aby toto specifikovala • UNIX norma definuje pomoc´ı13 pravidel velmi pˇresnˇe,jak by mˇelyvypa- dat n´azvypˇr´ıkaz˚ua form´atpˇrep´ınaˇc˚u.Napˇr´ıklad jm´enopˇr´ıkazu by mˇelo b´ytpouze mal´ymip´ısmeny, dlouh´e2–9 znak˚u,z pˇrenositeln´eznakov´esady.

52 Pˇrep´ınaˇcebez argument˚uby mˇelob´ytmoˇzn´ed´atdo skupiny za jedn´ımzna- kem ’–’. Atd.

• pouˇz´ıvat ˇc´ıslicejako pˇrep´ınaˇceje zastaral´e;je to nˇekdev normˇeSUSv3, i kdyˇzj´ato v n´ınenaˇsel. • pozor na Linux a jeho (ponˇekudzvl´aˇstn´ıa nestandardn´ı)permutov´an´ıargu- ment˚u

• pˇrep´ınaˇc -W by mˇel b´ytrezervovan´ypro vendor options, tj. pro nepˇrenositeln´a rozˇs´ıˇren´ı

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ˇrikaˇzd´em vol´an´ızpracuje a vr´at´ıdalˇs´ıpˇrep´ınaˇc.Pokud m´apˇ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´ısloprvn´ıhonezpracovan´ehoargumentu. • moˇzn´epˇrep´ınaˇcejsou zad´any v optstring, kdyˇzza znakem pˇrep´ınaˇcen´asleduje’:’, m´apˇrep´ınaˇcpovinnou hodnotu. • pˇrichybˇe(nezn´am´ypˇrep´ınaˇc,chyb´ıhodnota) vr´at´ı’?’, uloˇz´ı znak pˇrep´ınaˇcedo optopt a kdyˇz opterr nebylo nastaveno na nulu, vyp´ıˇsechybov´ehl´aˇsen´ı.

• obvykle se nejprve pomoc´ı getopt naˇctoupˇrep´ınaˇcea pak se vlastn´ımipro- stˇredkyzpracuj´ıostatn´ıargumenty; ˇcastojsou to jm´enasoubor˚u.

• je konvenc´ı,ˇzevolby v parametru optstring jsou setˇr´ıdˇen´e.

53 Pˇr´ıkladpouˇ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´ymzvykem je pˇridetekov´an´ınezn´am´ehopˇrep´ınaˇcenebo ˇspatn´ehoz´a- pisu parametr˚uprogramu vypsat struˇcnoun´apovˇedu,pˇr´ıpadnˇes odkazem na podrobnˇejˇs´ıdokumentaci, a ukonˇcitprogram s chybou, tj. s nenulovou n´avratovou hodnotou.

• pˇr´ıkladtak´eukazuje nebezpeˇcn´epouˇzit´ıfunkce strcpy

• z pouˇzit´ıfunkce getopt je vidˇet,ˇzeje stavov´a.Zpracovat dalˇs´ıpole argu- ment˚u,pˇr´ıpadnˇezaˇc´ıtopˇetod zaˇc´atku,je moˇzn´enastaven´ımextern´ıpro- mˇenn´e optreset na 1. • standardn´ı getopt zachov´apoˇrad´ıpˇrep´ınaˇc˚upˇrizpracov´an´ı • pˇripouˇzit´ınedefinovan´ehopˇrep´ınaˇcefunkce vyp´ıˇsechybu; to lze potlaˇcitna- staven´ım opterr na 0.

• pˇr´ıklad:shellov´yskript getopt/getopts.sh pˇrepsan´ydo jazyka C pomoc´ı getopt funkce, getopt/getopt.c

54 Dlouh´ytvar pˇrep´ınaˇc˚u

• poprv´ese objevilo v GNU knihovnˇe libiberty: --jm´enonebo --jm´eno=hodnota • argumenty se permutuj´ıtak, aby pˇrep´ınaˇcebyly na zaˇc´atku, napˇr. ls * -l je tot´eˇzjako ls -l *, standardn´ıchov´an´ılze doc´ılitnastaven´ımpromˇ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´enopˇ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´a n´asleduj´ıc´ıvlastnosti:

• pokud vˇsechny dlouh´epˇrep´ınaˇcemaj´ı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ˇcii s mezerou (napˇr´ıklad --color green) • pokud je nastaven flag, tak getopt long vrac´ı0, ˇc´ımˇzse tyto dlouh´epˇre- p´ınaˇcebez kr´atk´evarianty zpracuj´ıv jedn´evˇetvipˇr´ıkazu case • existuje i vol´an´ı getopt long only, kter´epovoluje i dlouh´epˇrep´ınaˇceuvozen´e jednou uvozovkou (-option)

• funkci getopt long je moˇzn´epouˇz´ıvat dvˇemizp˚usoby. Prvn´ızp˚usobje, ˇze kaˇzd´ydlouh´ypˇrep´ınaˇcm´akoresponduj´ıc´ıkr´atk´y– takto lze jednoduˇsepˇridat dlouh´epˇrep´ınaˇcedo existuj´ıc´ıho programu a je kompatibiln´ı s getopt. Druh´yzp˚usobumoˇzˇnujem´ıtsamostatn´edlouh´epˇrep´ınaˇce. V tom pˇr´ıpadˇe funkce vrac´ıvˇzdy0 (nekompatibilita s getopt) a promˇenn´a *flag se nastav´ı na val. • na konkr´etn´ımpˇr´ıkladuna n´asleduj´ıc´ıstr´anceje vidˇet,jak to cel´efunguje

55 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´aznampole 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´ıcindex nalezen´eho pˇrep´ınaˇcev longopts.

• toto je upraven´ypˇr´ıkladz manu´alov´estr´ankyna FreeBSD:

#include #include #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"); }

56 argc -= optind; argv += optind; return 0; }

Struktura klasick´ehoOS UNIX

uˇzivatelsk´yproces uˇzivatelsk´y n´avratpˇreruˇsen´ı 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´emaje pˇrevzatoz [Bach86], viz literatura. Zd˚urazˇnujedva ´ustˇredn´ı pojmy v modelu syst´emu UNIX – soubory a procesy. V dneˇsn´ıdobˇeto vypad´avelmi odliˇsnˇe,ale pro n´asstaˇc´ıtato z´akladn´ıpˇredstava. • UNIX rozliˇsujedva reˇzimy bˇehu procesoru: uˇzivatelsk´yreˇzim a reˇzimj´adra. V uˇzivatelsk´emreˇ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´ytpod- porov´any na hardwarov´e´urovni (procesorem). • procesy bˇeˇz´ıobvykle v uˇzivatelsk´emreˇzimu, do reˇzimu j´adrapˇ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´alese v reˇzimu j´adra oˇsetˇru- j´ıv´yjimeˇcn´estavy procesoru (v´ypadekstr´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ˇrenomonolitick´ymk´odem.P˚uvodnˇebylo po- tˇrebavygenerovat (tj. pˇreloˇzit ze zdrojov´ych text˚ua slinkovat) j´adropˇri zmˇenˇenˇekter´ehoparametru nebo pˇrid´an´ıovladaˇcezaˇr´ızen´ı.V novˇejˇs´ıch im- plementac´ıch je moˇznonastavovat parametry j´adra,nˇekdyi za bˇehu, pomoc´ı syst´emov´ych utilit bez nutnosti rekompilace j´adra.Modern´ıunixov´esyst´emy umoˇzˇnuj´ırozˇsiˇrovat k´odj´adraza bˇehu pomoc´ıtzv. modul˚uj´adra(loadable kernel modules). Napˇr´ıkladsyst´emFreeBSD 5.4-RELEASE m´a392 takov´ych modul˚u.

57 • existuj´ıdva zp˚usoby pr´aces 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ˇresvyrovn´avac´ı pamˇeti(buffers) po bloc´ıch, znakov´azaˇr´ızen´ı (napˇr.termin´aly)umoˇzˇnuj´ıpracovat s jednotliv´ymibajty a nepouˇz´ıvaj´ıvy- rovn´avac´ıpamˇet’. • j´adronen´ısamostatn´yproces, ale je ˇc´ast´ıkaˇzd´ehouˇzivatelsk´ehoprocesu. Kdyˇzj´adronˇecovykon´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´ymkontextem, identifikovan´yjednoznaˇcn´ymˇc´ıslem(process ID, PID); jin´ymislovy ,,k´oda data v pamˇeti” • vl´akno() je syst´emov´yobjekt, kter´yexistuje uvnitˇr procesu a je charakterizov´ansv´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´ehoform´atuobsahuj´ı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´aknajednoho procesu mohou bˇeˇzetna r˚uzn´ych procesorech.

• kontext je pamˇet’ov´yprostor procesu, obsah registr˚ua datov´estruktury j´adrat´ykaj´ıc´ıse dan´ehoprocesu • jinak ˇreˇceno – kontext procesu je jeho stav. Kdyˇzsyst´emvykon´av´aproces, ˇr´ık´ase, ˇzebˇeˇz´ıv kontextu procesu. J´adro(klasick´e)obsluhuje pˇreruˇsen´ıv kontextu pˇreruˇsen´ehoprocesu.

• vl´aknase dostala do UNIXu aˇzpozdˇeji,p˚uvodnˇev nˇemexistovaly pouze procesy, kter´emˇelyz dneˇsn´ıhopohledu pouze jedno vl´akno.Moˇznostpouˇz´ıt v procesu v´ıcevl´aken byla zavedena, protoˇzese uk´azalo,ˇzeje vhodn´em´ıt v´ıceparaleln´ıch lini´ıv´ypoˇctunad sd´ılen´ymidaty. • pamˇet’ov´eprostory proces˚ujsou navz´ajemizolovan´e,ale procesy spolu mohou komunikovat. Pozdˇejise dozv´ıme,ˇzemohou i ˇc´asteˇcnˇesd´ıletpamˇet’. • procesy jsou entity na ´urovni j´adra,ale vl´akna mohou b´ytˇc´asteˇcnˇenebo zcela implementov´anaknihovn´ımifunkcemi. V pˇr´ıpadˇeimplementace pomoc´ı

58 knihovn´ıch fuknc´ıto znamen´a,ˇzevl´akna nemus´ıj´adrov˚ubec podporovat. S vl´akny je spojena menˇs´ıreˇzieneˇ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´emBSD tedy nem´ave znaku ˇcerta,ale d´emona.

J´adro,reˇzimy, pˇreruˇsen´ı(klasick´yUNIX)

• procesy typicky bˇeˇz´ıv uˇzivatelsk´emreˇzimu • syst´emov´evol´an´ızp˚usob´ıpˇrepnut´ıdo reˇzimu j´adra • proces m´apro kaˇzd´yreˇzimsamostatn´yz´asobn´ık • j´adroje ˇc´ast´ıkaˇzd´ehouˇzivatelsk´ehoprocesu, 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´ehoprocesu • klasick´ej´adro je nepreemptivn´ı

• j´adronen´ıoddˇelen´amnoˇzinaproces˚u,bˇeˇz´ıc´ıch paralelnˇes uˇziva- telsk´ymiprocesy, ale je ˇc´ast´ıkaˇzd´ehouˇzivatelsk´ehoprocesu. • pˇrechod mezi uˇzivatelsk´ymreˇzimema reˇzimemj´adranen´ıpˇrepnut´ıkontextu – proces bˇeˇz´ıpoˇr´adv tom sam´em

• pˇreruˇsen´yproces nemusel pˇreruˇsen´ıv˚ubec zp˚usobit • v reˇzimu j´adram˚uˇzeproces pˇristupovat i k adres´amj´adra,kter´az uˇzivatelsk´e- ho reˇzimu pˇr´ıstupn´anejsou; takt´eˇzm˚uˇzepˇristupovat k instrukc´ım(napˇr.in- strukce manipuluj´ıc´ıse stavov´ymregistrem), jejichˇzvykon´an´ıv uˇzivatelsk´em reˇzimu vede k chybˇe

• pˇreruˇsovac´ırutina se nem˚uˇzezablokovat, protoˇzet´ımby zablokovala proces; proces se totiˇzm˚uˇzezablokovat jen ze sv´evlastn´ıv˚ule.Modern´ıunixy dnes pouˇz´ıvaj´ıinterrupt vl´akna,v jejichˇzkontextu se mohou drivery zablokovat. • to, ˇzeklasick´eunixov´ej´adroje nepreemptivn´ıznamen´a,ˇze jeden proces nem˚uˇzezablokovat jin´yproces

59 • pˇriobsluze pˇreruˇsen´ıse m˚uˇzest´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´anav z´asobn´ıkukontextov´ych vrstev. • u modern´ıch kernel˚uje situace ˇcastovelmi rozd´ıln´a– obsluha pˇre- ruˇsen´ı,preemptivnost kernelu atd.; k nˇekter´ymvˇecemse moˇzn´a dostaneme pozdˇejibˇehemsemestru

Vol´an´ısluˇzeba 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ˇzadujeproveden´ısyst´emov´esluˇzby, pomoc´ısyst´e- mov´ehovol´an´ıpˇred´aˇr´ızen´ıj´adru.J´adroje kus k´odu sd´ılen´yvˇsemiprocesy (ovˇsempˇr´ıstupn´yjen pro ty, kter´ejsou pr´avˇev reˇzimu j´adra).J´adrotedy nen´ısamostatn´yprivilegovan´yproces, ale vˇzdybˇeˇz´ıv r´amcinˇekter´ehopro- cesu (toho, kter´ypoˇz´adalj´adroo sluˇzbu,nebo toho, kter´ybˇeˇzelv 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´eprocesy (oznaˇco- van´ejako kernel threads), kter´ebˇeˇz´ıcelou dobu v reˇzimu j´adra.Naprost´a vˇetˇsinasyst´emov´ych proces˚uvˇsakbˇeˇz´ıv uˇzivatelsk´emreˇzimu a liˇs´ıse jen t´ım,ˇzemaj´ıvˇetˇs´ıpˇr´ıstupov´apr´ava. Pl´anovaˇcproces˚upˇrep´ın´amezi procesy a t´ımumoˇzˇnujebˇehv´ıceproces˚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ˇzepˇripˇrepl´anov´an´ıdostat i na jin´yprocesor). • v distribuovan´emoperaˇcn´ımsyst´emu m´aj´adroobvykle formu mikroj´adra, tj. zajiˇst’uje pouze nejz´akladnˇejˇs´ısluˇzby ˇr´ızen´ıprocesoru, pˇridˇelov´an´ıpamˇeti

60 a komunikace mezi procesy. Vyˇsˇs´ı syst´emov´esluˇzby, kter´ejsou v UNIXu souˇc´ast´ıj´adra (napˇr.pˇr´ıstupk syst´emu soubor˚u)jsou realizov´any speci´aln´ımi procesy (servery) bˇeˇz´ıc´ımi v uˇzivatelsk´emreˇzimu procesoru. J´adropˇred´a poˇzadavek uˇzivatelsk´ehoprocesu pˇr´ısluˇsn´emu serveru, kter´ym˚uˇzebˇeˇzeti na jin´emuzlu s´ıtˇe. • dostupn´ych mikrokernel˚uje v dneˇsn´ıdobˇemnoho. M˚uˇzetezkusit napˇr´ıklad Minix (unix-like v´yukov´ysyst´em),pˇr´ıpadnˇesyst´emHURD, kter´ybˇeˇz´ınad mikroj´adremMach.

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´odprogramu. – syst´emov´avol´an´ımaj´ıtak´etvar vol´an´ıfunkce. Pˇr´ısluˇsn´a funkce ale pouze zpracuje argumenty vol´an´ıa pˇred´aˇr´ızen´ı j´adrupomoc´ıinstrukce synchronn´ıhopˇreruˇsen´ı.Po n´avratu z j´adrafunkce uprav´ıv´ysledeka pˇred´aho volaj´ıc´ımu. • standardy tyto kategorie nerozliˇsuj´ı– z hlediska program´atora je jedno, zda urˇcitoufunkci provede j´adronebo knihovna.

• zjednoduˇsenˇelze ˇr´ıci,ˇze syst´emov´evol´an´ı je funkce, kter´ajen uprav´ı sv´e argumenty do vhodn´epodoby, pˇrepnereˇzimprocesoru a skuteˇcnoupr´aci nech´ana j´adru.Nakonec zase uprav´ıv´ysledek. Knihovn´ıfunkce m˚uˇzea nemus´ıvolat j´adro,ale vˇzdysama dˇel´anˇejakou netrivi´aln´ıˇcinnost v uˇzivatelsk´emreˇzimu.

• v assembleru je moˇzn´ezavolat vol´an´ıj´adrapˇr´ımo • API j´adraje definovan´ena ´urovni vol´an´ıfunkc´ıstandardn´ıknihovny, nikoliv na ´urovni pˇreruˇsen´ıa datov´ych struktur pouˇz´ıvan´ych tˇemitofunkcemi pro pˇred´an´ıˇr´ızen´ı j´adru. Mechanismus pˇrepnut´ı mezi uˇzivatelsk´ymreˇzimema reˇzimemj´adrase totiˇzm˚uˇzeliˇsitnejen v z´avislosti na hardwarov´eplatformˇe, ale i mezi r˚uzn´ymiverzemi syst´emu na stejn´emhardwaru.

61 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´emsyst´emov´emvol´an´ıje k´odchyby v glob´aln´ı promˇenn´e extern int errno; • ´uspˇeˇsn´evol´an´ınemˇen´ıhodnotu v errno! Je tedy tˇrebanejprve otestovat n´avratovou hodnotu a pak teprve errno. • chybov´ehl´aˇsen´ıpodle hodnoty v errno vyp´ıˇsefunkce void perror(const char *s ); • textov´ypopis chyby s dan´ymˇc´ıslemvr´at´ıfunkce char *strerror(int errnum );

• v Solarisu je hodnota errno ve skuteˇcnostiknihovnou libc definovan´ajako dereferencovan´ypointer na integer (specifick´ypro dan´yuserland thread) a hodnota se nastavuje ihned po v´ystupuz instrukce pro syst´emov´evol´an´ı. Napˇr.na i386 architektuˇreje hodnota errno po n´avratuz kernelu (po do- konˇcen´ıinstrukce sysenter) uloˇzenav registru eax (pˇredvol´an´ımv n´ıbylo ˇc´ıslosyscallu). Je to tedy knihovna libc kdo je zodpovˇedn´yza to, ˇzeprogram uvid´ıspr´avnouhodnotu errno. • funkce pro pr´acis vl´akny pthread * nenastavuj´ı errno, ale vrac´ıbud’ nulu (´uspˇech) nebo pˇr´ımok´odchyby.

• pro nˇekter´avol´an´ı m˚uˇzem´ıt smysl i n´avratov´ahodnota -1. Pak je tˇreba nejprve nastavit errno = 0 a po n´avratuzkontrolovat, zda se errno zmˇenilo. Napˇr.funkce strtol vrac´ıpˇrichybˇe0, coˇzje platn´ahodnota i pro spr´avn´y v´ysledek(a −1 je samozˇrejmˇeplatn´yv´ysledektak´e). • je tedy vˇzdynutn´esi pˇreˇc´ıstmanu´alovou str´ankupro pˇr´ıˇsluˇsn´evol´an´ınebo knihovn´ıfunkci

• pozn.: ´uspˇeˇsnostfunkc´ıze stdio.h je tˇrebatestovat pomoc´ı int ferror(FILE *stream ), protoˇzejinak nelze rozliˇsitmezi chybou a kon- cem streamu. Vzhledem k tomu, ˇzetyto funkce nepouˇz´ıv´ame(kromˇe printf a fprintf na stdout, resp. stderr), nemˇelibyste ji potˇrebovat.

62 Skupina funkc´ız err(3)

• pomocn´efunkce pro v´ypischybov´ych hl´aˇsen´ıa pˇr´ıpadn´e ukonˇcen´ıprogramu • m´ısto perror() a exit() v´amstaˇc´ıjedna funkce • void err(int status, const char *fmt, ...); – vyp´ıˇsejm´enoprogramu, form´atovan´yˇretˇezec,a chybu podle aktu´aln´ıhodnoty errno – ukonˇc´ıprogram s n´avratovou hodnotou ze status • void warn(const char *fmt, ...); – stejn´ejako err(), ale program neukonˇc´ı • existuj´ıdalˇs´ıpodobn´efunkce, viz manu´alov´astr´anka • funkce poch´azej´ıze 4.4BSD

• vˇetˇs´ıprogramy podobn´efunkce ˇcastonepouˇz´ıvaj´ı,napˇr´ıkladproto, ˇzestejnˇe potˇrebuj´ıprov´estr˚uzn´eukonˇcovac´ıpr´acepˇred skonˇcen´ımprogramu, takˇze maj´ıpodobn´efunkce vlastn´ı.Pro jin´eprogramy jsou ale tyto funkce ide´aln´ı, protoˇzemaj´ırozumn´yv´ystupa ˇsetˇr´ıˇr´adkyvaˇsehok´odu.

• tyto funkce nemus´ıb´ytvˇsude,napˇr´ıkladnejsou v libc.so pro Solaris 10 (ale jsou v Solarisu 11). Jsou na BSD syst´emech a v linuxov´ych distribuc´ıch. Tyto funkce nejsou souˇc´ast´ıSUS, takˇzeani na certifikovan´ych UNIX syst´emech se nelze spolehnout na jejich pˇr´ıtomnost. Reˇsen´ımjeˇ kontrolovat jejich existenci v pˇredkompilaˇcn´ımskriptu a pˇr´ıpadnˇem´ıtjejich verzi souˇc´ast´ızdrojov´ych k´od˚uprogramu pro pˇr´ıpadˇzenebudou na c´ılov´emsyst´emu nalezeny.

• pˇr´ıklad(viz tak´e err/err.c ):

#include #include

int main(void) { errno = 13; err(3, "ggr %s", "GRR"); printf("after err()\n"); return (0); }

63 $ ./a.out a.out: ggr GRR: Permission denied $ echo $? 3

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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

64 Users and groups

beran:x:1205:106:Martin Beran:/home/beran:/bin/bash

The fields, in order from left to right: user name, hashed password (today in /etc/shadow or elsewhere), user ID (aka UID); primary group ID (aka GID), full name, home directory, login shell Note that a superuser (root) has always UID 0.

sisal:*:106:forst,beran

The fields, in order from left to right: group name, group password (not used today), group ID (GID), list of group members

• informace o uˇzivatel´ıch v souborech /etc/passwd, a /etc/group jsou zpra- cov´av´any r˚uzn´ymisyst´emov´ymiprogramy, napˇr. login (pˇrihl´aˇsen´ıdo syst´e- mu na z´akladˇeuˇzivatelsk´ehojm´enaa hesla) nebo su (zmˇenaidentity). 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´ı, pouze uˇzivatel root m´apr´avo pro ˇcten´ı a z´apis. Tedy pouze privilegovan´epro- gramy jako login nebo sshd mohou z tohoto souboru ˇc´ıstnebo zapisovat (program passwd bˇeˇz´ıpod uˇzivatelem root d´ıky setuid bitu nastaven´emna souboru programu, viz pozn´amkyna stranˇe 71). Takto jsou hesla separo- van´aod veˇrejnˇepˇr´ıstupn´ych informac´ı,nav´ıcsoubor kter´yhesla obsahuje, je ukl´ad´av zahaˇsovan´e/zaˇsifrovan´eformˇe,takˇzenejsou pˇr´ımoˇciteln´a.Na BSD syst´emech (napˇr.FreeBSD, Mac OS X) se m´ısto /etc/shadow pouˇz´ıv´a soubor /etc/master.passwd. • Soubor /etc/shadow je podobnˇestrukturovan´yjako /etc/passwd. Jeden z´aznamobsahuje vˇetˇsinoun´asleduj´ıc´ıpoloˇzky(Solaris): uˇzivatelsk´ejm´eno, zahaˇsovan´eheslo (spolu s indik´atoremˇzedan´y´uˇcetje zablokovan´y),posledn´ı modifikace hesla, minimum dn´ıpoˇzadovan´ych mezi zmˇenouhesla, maximum dn´ıpo kter´eje heslo platn´e,poˇcetdn´ıpo kter´ych je uˇzivatel varov´ano expi- raci hesla, poˇcetpovolen´ych dn´ıneaktivity uˇzivatele, absolutn´ıˇcasexpirace uˇzivatele, poˇcetne´uspˇeˇs´ych pokus˚uo nalogov´an´ıtohoto uˇzivatele. • Hesla v /etc/shadow jsou uloˇzenatakov´ymzp˚usobem, aby pokud se povede nˇekomu soubor z´ıskat, mˇel zt´ıˇzenoupr´acipˇriodhadov´an´ı hesel. P˚uvodn´ı

65 (cleartext) heslo se proˇzenejednosmˇernoukryptografickou funkc´ı(kter´aje nav´ıcparametrizovateln´a,ˇc´ımˇzse v´ypoˇcetn´ıa prostorov´asloˇzitostpro ´utok hrubou silou jeˇstˇezv´yˇs´ı)a uloˇz´ıse do /etc/shadow v t´etoformˇe.Ovˇeˇrov´an´ı hesla pak funguje tak ˇze,se na cleartext heslo aplikuje dan´afunkce s dan´ymi parametry a v´ysledekse porovn´as polem hesla v /etc/shadow. Pokud jsou stejn´e,probˇehlaautentizace ´uspˇeˇsnˇe.P˚uvodnˇenavrˇzen´afunkce pˇrestalas roz- vojem procesor˚ustaˇcit,takˇzese dnes pouˇz´ıvaj´ıfunkce MD5, SHA1, Blowfish a dalˇs´ı.Poloˇzka hesla v /etc/shadow je pak vnitˇrnˇestrukturovan´apomoc´ı speci´aln´ıch znak˚u,takˇzeprogramy ovˇeˇruj´ıc´ıheslo v´ı,jakou funkci a s jak´ymi parametry pouˇz´ıt.Vˇetˇsinasyst´em˚uumoˇzˇnujeglob´aln´ıkonfiguraci pouˇzit´ych funkc´ıa jejich parametr˚u.

• existuj´ı i jin´esyst´emy, kter´e(nejen) pro autentizaci /etc/passwd nemus´ı v˚ubec pouˇz´ıvat, napˇr´ıkladNIS (Network Information Service) nebo LDAP (Lightweight Directory Access Protocol).

• skupina uˇzivatele uveden´av /etc/passwd se naz´yv´a prim´arn´ı. Tuto skupi- novou identifikaci 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 (supplementary) a rozˇsiˇruj´ıpˇr´ıstupov´apr´ava uˇzivatele: skupinov´ypˇr´ıstupje povolen ke vˇsemobjekt˚um,jejichˇzskupinov´yvlastn´ıkje roven bud’ prim´arn´ı, nebo jedn´ez doplˇnkov´ych skupin. • p˚uvodnˇemˇelv UNIXu kaˇzd´yuˇzivatel vˇzdyaktivn´ıpouze jednu skupinovou identitu. Po nalogov´an´ıbyl ve sv´eprim´arn´ıskupinˇe,pro z´ısk´an´ıpr´avjin´e skupiny bylo tˇrebase do n´ıpˇrepnoutpˇ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ˇrebapro pˇr´ıstupk soubor˚ummˇenitprim´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ˇretsoubory s jinou skupinovou identitou, neˇzje prim´arn´ıskupina uˇzivatele. Lok´alnˇepro urˇcit´yadres´aˇrtoho lze dos´ahnoutnastaven´ımskupinov´ehovlastn´ıka adres´aˇrena poˇzadovanou skupinu a nastaven´ımbitu 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ˇenitpoˇzadovanou skupinu u adres´aˇre.Pˇr´ıkladvytvoˇren´ıtakov´ehoadres´aˇrena Solarisu (pˇr´ıkaz chown mus´ıb´yt proveden pod uˇzivatelem root):

# mkdir mydir # chown :lidi mydir # ls -ald mydir drwxr-xr-x 2 root lidi 4 Nov 2 20:01 mydir # cd mydir/ mydir # touch foo mydir # ls -ald foo -rw-r--r-- 1 root root 0 Nov 2 20:01 foo mydir # chmod g+s . mydir # ls -ald . drwxr-sr-x 2 root lidi 4 Nov 2 20:01 . mydir # touch bar mydir # ls -ald bar -rw-r--r-- 1 root lidi 0 Nov 2 20:01 bar mydir #

66 • 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´ıkladna FreeBSD je pˇr´ıkaz newgrp pˇr´ıstupn´yuˇzjen superuˇzivateli (kv˚ulivol´an´ı setgroups).

Name service switch

• today’s systems are not confined to only using /etc/passwd and /etc/groups • such systems have databases (passwd, groups, protocols, . . . ) • database data come from sources (files, DNS, NIS, LDAP, . . . )

• file nsswitch.conf defines what databases use what sources • library functions must support this, obviously • it is possible to combine some sources, eg. users may be first be searched in /etc/passwd, then in LDAP • came first with Solaris, other systems took over the idea

• syst´emy maj´ıtypicky manu´alovou str´anku nsswitch.conf(4), kde lze nal´ezt podrobnosti v z´avislostina konkr´etn´ımoperaˇcn´ımsyst´emu, vˇcetnˇeAPI, po- moc´ıkter´ehose pracuje s jednotliv´ymidatab´azemi.Napˇr´ıklad,s datab´az´ı passwd pracuj´ıstandardn´ıvol´an´ı getpwnam(3), getpwent(3) a dalˇs´ı- nen´ı proto potˇrebazpracov´avat tyto soubory (datab´aze)sami. • zde je ˇc´astskuteˇcn´ehosouboru 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

67 Z´ısk´av´an´ı´udaj˚uo uˇzivatel´ıch/skupin´ach

• struct passwd *getpwnam(const char *name) vrac´ıstrukturu reprezentuj´ıc´ıuˇzivatele.

• struct passwd *getpwuid(uid t uid) vrac´ıstrukturu reprezentuj´ıc´ıuˇzivatele podle UID.

• void setpwent(void) • void endpwent(void) • struct passwd *getpwent(void) slouˇz´ık proch´azen´ıpoloˇzekv datab´aziuˇzivatel˚u. setpwent nastav´ıpozici na zaˇc´atek, getpwent z´ısk´adalˇs´ıpoloˇzku, endpwent dealokuje prostˇredkypouˇzit´epro proch´azen´ı seznamu.

• tyto funkce funguj´ınez´avislena tom jak z jak´edatab´azebyly z´ısk´any infor- mace o dan´emuˇzivateli. • vˇsechny tyto funkce jsou souˇc´ast´ıPOSIX 1003.1-2008 (sekce XSH) • setpwent je tˇrebazavolat pˇredprvn´ımvol´an´ım getpwent

• analogicky exituj´ıfunkce getgrnam a getgrent kter´ez´ısk´avaj´ıinformace o skupin´ach.

• pro prohled´av´an´ıa v´ypisdatabaz´ılze pouˇz´ıtprogram getent. Napˇr. k nale- zen´ız´aznamu uˇzivatele a skupiny root:

$ getent passwd root root:x:0:0:Super-User:/root:/sbin/sh $ getent group root root::0:

68 Testov´an´ıpˇr´ıstupov´ych pr´av • uˇzivatel je identifikov´anˇc´ıslemuˇzivatele (UID) a ˇc´ıslyskupin, do kter´ych patˇr´ı(primary GID, supplementary GIDs). • tuto identifikaci dˇed´ıkaˇzd´yproces dan´ehouˇzivatele.

• soubor S m´avlastn´ıka (UIDS) a skupinov´ehovlastn´ıka (GIDS). • algoritmus testov´an´ıpˇr´ıstupov´ych pr´avpro 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 ˇclenaskupiny else . . . pr´ava ostatn´ıch

• procesy superuˇzivatele root mohou mˇenitsvoji 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´enaa hesla spust´ıshell s uˇzivatelskou identitou (pomoc´ıvol´an´ı setuid – viz dalˇs´ıslajdy). • z algoritmu plyne, ˇzepro 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´ıceneˇzuˇzivatelsk´apr´ava. Podobnˇe pr´ava ostatn´ıch se nepouˇzij´ı, jestliˇzese shoduje skupinov´aidentita. Tedy pokud m´am˚ujsoubor nastaveny pr´ava ---rwxrwx, nemohu ho ˇc´ıst, zapisovat ani spustit, dokud nastaven´ıpr´avnezmˇen´ım.

• ˇc´ımd´alv´ıcsyst´em˚use odkl´an´ıod klasick´ehomodelu, kdy mnoho proces˚u bˇeˇzelopod uˇzivatelem s UID 0 a pˇri bezpeˇcnostn´ıchybˇev takov´eaplikaci ˇcasto´utoˇcn´ıkz´ıskal vl´adunad cel´ymsyst´emema zav´adˇej´ımodely jako je least privilege model v Solarisu nebo privilege separation a systrace v OpenBSD. • opakov´an´ız prvn´ıhoroˇcn´ıku– aby uˇzivatel mohl smazat soubor, mus´ım´ıt pr´avo z´apisudo dan´eho adres´aˇre, protoˇzeto je ten “soubor”, co se mˇen´ı. Pr´ava k mazan´emu souboru nejsou podstatn´a; to ˇzev´asshell upo- zorn´ı,ˇzemaˇzetesoubor, ke kter´emu nem´atepr´avo z´apisu, je pouze vˇectoho shellu. Je to logick´e– pokud si nastav´ıtesoubor jako read-only, shell usuzuje, ˇzeho asi norm´alnˇemazat nechcete. Viz pˇr´ıklad pod t´ımto odstavcem. Uni- xov´esyst´emy nemaj´ıdelete-like operaci na soubor, smaz´an´ısouboru nastane automaticky tehdy, kdyˇzna soubor nen´ıˇz´adn´yodkaz z adres´aˇrov´e struktury, a nikdo soubor jiˇznem´aotevˇren´y.

69 $ whoami janp $ ls -ld janp-dir drwx------2 janp staff 512 Mar 23 12:12 janp-dir/ $ ls -l janp-dir total 0 -rw-r--r-- 1 root root 0 Mar 23 12:11 root_wuz_here.txt $ rm janp-dir/root_wuz_here.txt rm: janp-dir/root_wuz_here.txt: override protection 644 (yes/no)? yes $ ls janp-dir/root_wuz_here.txt janp-dir/root_wuz_here.txt: No such file or directory

• pokud ale root vytvoˇr´ı v adres´aˇri janp-dir sv˚ujpodadres´aˇra tam vloˇz´ı sv˚ujsoubor, uˇzivatel janp uˇznem˚uˇzeadres´aˇr janp-dir a jeho obsah smazat, protoˇze: – podadres´aˇrnelze smazat protoˇzenen´ıpr´azdn´y – a dan´ysoubor nelze smazat z toho d˚uvodu, ˇze janp nen´ıvlastn´ıkem podadres´aˇre. • Pokud odeberu adres´aˇriread bit, nen´ımoˇzn´eˇc´ıstjeho obsah, tedy prov´adˇet v´ypissoubor˚uv nˇemobsaˇzen´ych. Pokud ale zn´amjm´eno souboru v adres´aˇri a execute bit je nastaven, mohu soubor pˇreˇc´ıst:

$ mkdir foo $ ls -ald foo drwxr-xr-x 2 vladimirkotal staff 68 Nov 5 14:37 foo $ touch foo/bar $ file foo/bar foo/bar: empty $ ls foo bar $ chmod u-r foo $ ls foo ls: foo: Permission denied $ file foo/bar foo/bar: empty

• existuje situace, kdy ani pr´avo z´apisu(a execute) pro adres´aˇrnestaˇc´ı.To se pouˇz´ıv´au tmp adres´aˇr˚u,do kter´ych m˚uˇzekaˇzd´yps´at,ale nen´ıˇz´adouc´ı situace, kdy by si uˇzivatel´enavz´ajemmazali soubory. K tomu se pouˇz´ıv´atzv. sticky bit (01000). Syst´emy maj´ıvetˇsinoumanu´alovou str´anku sticky, kde je funkce sticky bitu popsan´a.Na v´ypisu ls je oznaˇcovan´yjako t:

$ ls -ld /tmp drwxrwxrwt 7 root root 515 Mar 23 12:22 /tmp

70 Re´aln´ea efektivn´ıUID/GID • u kaˇzd´ehoprocesu se rozliˇsuje: – re´aln´eUID (RUID) – skuteˇcn´yvlastn´ıkprocesu – efektivn´ıUID (EUID) – uˇzivatel, jehoˇzpr´ava proces pouˇz´ıv´a – uschovan´eUID (saved SUID) – p˚uvodn´ıefektivn´ıUID • podobnˇese rozliˇsujere´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 a saved UID procesu na UID vlastn´ıka programu, RUID se nezmˇen´ı. • podobnˇeSGID bit ovlivˇnujeEGID procesu. • pˇrikontrole pˇr´ıstupov´ych pr´avse 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ˇzebˇeˇzn´yuˇzivatel mˇenita druh´yz nich ani ˇc´ıst.Dalˇs´ıpˇr´ıkladje program su. Ten mus´ım´ıtpr´avo libovolnˇezmˇenituˇzivatelskou a skupinovou identitu, coˇzje privilegium proces˚us UID 0.

• SUID a SGID programy by mˇelyb´ytpeˇclivˇenaprogramov´any, aby dovolily pouze ty operace, pro kter´ejsou urˇceny, a neumoˇznilyzneuˇz´ıtjejich privilegia pro neopr´avnˇen´eakce (napˇr.spuˇstˇen´ırootovsk´ehoshellu). Zkuˇsenostukazuje, ˇzetyto programy jsou jednou z nejˇcastˇejˇs´ıch pˇr´ıˇcinbezpeˇcnostn´ı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´ıstopro generov´an´ıbezpeˇcnostn´ıch chyb protoˇzedobˇre,tj. 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ˇzezmˇenitsv´eRUID nebo uschovan´eSUID (vyj´ımka je pˇrivol´an´ı exec, viz strana 131) – proces m˚uˇzevˇzdyzmˇenitsv´eEUID na to z RUID nebo z uschovan´eho UID. Toto zaruˇcuje,ˇzev SUID programu je moˇzn´elibovolnˇemˇenitEUID mezi t´ımp˚uvodn´ımkter´ymproces z´ıskal pr´ava vlastn´ıka a mezi UID skuteˇcn´ehouˇzivatele kter´ydan´yproces spustil.

71 – root m˚uˇzevˇsechno, a kdyˇzzmˇen´ıRUID, tak se z´aroveˇnzmˇen´ıi ucho- van´eUID – nemˇeloby smysl mˇenitjen jedno z nich kdyˇzkter´ekoli m˚uˇzetepouˇz´ıtpro nastaven´ıEUID.

Identifikace vlastn´ıka procesu

• uid t getuid(void) vrac´ıre´aln´euser ID volaj´ıc´ıhoprocesu. • uid t geteuid(void) vrac´ıefektivn´ıuser ID volaj´ıc´ıhoprocesu. • gid t getgid(void) vrac´ıre´aln´egroup ID volaj´ıc´ıhoprocesu. • gid t getegid(void) vrac´ıefektivn´ıgroup ID volaj´ıc´ıhoprocesu. • int getgroups(int gidsz, gid t glist []) – do glist d´anejv´yˇse gidsz supplementary group IDs volaj´ıc´ıhoprocesu a vr´at´ıpoˇcet vˇsech GIDs procesu.

• pro re´aln´eUID je vol´an´ı getuid, vol´an´ı getruid neexistuje • getgroups: kdyˇz gidsz == 0, jen vr´at´ı poˇcetskupin. Kdyˇz 0 < gidsz < #skupin, vr´at´ı -1. • v UNIXu je mnoho typ˚ujako uid_t, gid_t, size_t, apod. Vesmˇesjsou to celoˇc´ıseln´etypy, ˇcastoje najdete v /usr/include/sys/types.h • Solaris m´apˇr´ıkaz pcred, kter´yjednoduˇsezobraz´ı informace o identifikaci procesu:

$ pcred 5464 5464: e/r/suid=1993 e/r/sgid=110 groups: 33541 41331 110

72 Zmˇenavlastn´ıka procesu

• int setuid(uid t uid ); – v procesu s EUID == 0 nastav´ıRUID, EUID i saved-SUID na uid – 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´ytpouˇzitojen superuˇzivatelsk´ymprocesem.

• o nastaven´ıUID pro proces s EUID 0 viz tak´epozn´amkyna stranˇe 71. • co v´yˇseuveden´etedy znamen´a:proces s efektivn´ımi pr´avysuperuˇzivatele m˚uˇzelibovolnˇemˇenitidentitu. Ostatn´ıprocesory mohou pouze stˇr´ıdatsv´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ˇriopaˇcn´em poˇrad´ı vol´an´ıby proces po proveden´ı setuid uˇznemˇelpr´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´atitk EUID, se kter´ymbyl spuˇstˇen(po t´e,co doˇcasnˇenastavil sv´eEUID na UID uˇzivatele, kter´yproces spustil, tj. na RUID).

• pokud tedy jako root vytvoˇr´ıteSUID program a v nˇemzavol´ate setuid pro jak´eholiUID mimo 0, jiˇzse v programu k EUID==0 nem˚uˇzetevr´atit(je to logick´e– pˇredstavte si situaci, kdy se uˇzivatel loguje do syst´emu). V tom pˇr´ıpadˇebyste museli pouˇz´ıtvol´an´ı seteuid, kter´enastavuje pouze EUID.

• pˇr´ıklad: setuid/screate-file.c

73 Syst´emsoubor˚u

• adres´aˇretvoˇr´ıstrom, spolu se soubory acyklick´ygraf (na jeden soubor m˚uˇzeexistovat v´ıceodkaz˚u). • kaˇzd´yadres´aˇrnav´ıcobsahuje odkaz na sebe ’.’ (teˇcka) a na nadˇrazen´yadres´aˇr’..’ (dvˇeteˇcky). • pomoc´ırozhran´ısyst´emu soubor˚use pˇristupujei k dalˇs´ım entit´amv 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´adraje kaˇzd´yobyˇcejn´ysoubor pole bajt˚u. • vˇsechny (i s´ıt’ov´e)disky jsou zapojeny do jednoho stromu.

• zaˇr´ızen´ı, soubory v /proc, termin´aly, pamˇet’ atd. jsou vˇsechno jeden typ soubor˚u- speci´aln´ısoubory. Dalˇs´ıtypy soubor˚u- regul´arn´ısoubor (hardlink), adres´aˇr,pojmenovan´aroura, socket, symbolick´ylink. • novˇevytvoˇren´yadres´aˇrm´ana sebe 2 odkazy – jeden z nadˇrazen´ehoadres´aˇre, a jeden s´amna sebe, ’.’:

$ mkdir test $ ls -ld test drwx------2 janp staff 512 Mar 23 12:46 test

• root m˚uˇzev nˇekter´ych syst´emech strukturu adres´aˇr˚uzacyklit, ale t´ımzmate utility pro proch´azen´ı filesyst´emu; moc se cyklick´estruktury nepouˇz´ıvaj´ı. Symbolick´elinky na adres´aˇrefunguj´ıvˇsude. • pojmenovan´eroury (viz strana 94) lze pouˇz´ıti mezi procesy, kter´enejsou pˇr´ıbuzenskyspˇ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ˇreskter´eprob´ıh´as´ıt’ov´akomuni- kace, se v syst´emu soubor˚uneobjevuj´ı.S´ıt’ov´akomunikace zaˇc´ın´ana stranˇe 179.

• 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´adrusyst´emu a bˇeˇz´ıc´ıch procesech ve formˇetextov´ych soubor˚u.

74 • 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ˇcepˇ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ˇetzmiz´ı.

Jednotn´yhierarchick´ysyst´emsoubor˚u

/

dev etc usr home tty

• svazek (angl. file system) je ˇc´astsouborov´ehosyst´emu, kterou lze samostatnˇe vytvoˇrit,pˇripojit, zruˇsit...Kaˇzd´yfilesyst´emm˚uˇzem´ıtjinou vnitˇrn´ıstrukturu (s5, ufs, ext2, xfs, atd.) a m˚uˇzeb´ytuloˇzenna lok´aln´ımdisku nebo na jin´em poˇc´ıtaˇcia pˇr´ıstupn´ypo s´ıti(nfs, afs). • po startu j´adraje 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ˇeheminicializace syst´emu, kdy se typicky ˇr´ıd´ıobsahem souboru /etc/fstab. Pˇredzastaven´ım syst´emu se filesyst´emy odpojuj´ıpˇr´ıkazem umount. • dalˇs´ımoˇznostje pˇripojen´ıfilesyst´emu na ˇz´adostpˇriprvn´ımpˇr´ıstupua 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.

75 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ˇrendomovsk´ych adres´aˇr˚u /var/adm . . . administrativn´ısoubory (ne na BSD) /usr/include . . . hlaviˇckov´esoubory pro 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ˇristartu 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ˇcastosamostatn´y filesyst´em,ˇc´ımˇzjeho obsah nen´ıdostupn´ybˇehemstartu syst´emu.

• s v sbin znaˇc´ı,,system”, ne SUID. Jsou to bin´arky, u kter´ych se pˇredpokl´ad´a, ˇzeje bˇeˇzn´yuˇzivatel nebude typicky potˇrebovat.

• podstrom /usr obsahuje soubory, kter´ese nemˇen´ı pˇribˇeˇzn´emprovozu a nejsou z´avisl´ena konkr´etn´ımpoˇc´ıtaˇci.Proto by mˇelj´ıtsd´ıletread-only. Na sv´estanici doma ho ale vˇetˇsinoubudete m´ıtread-write.

• /lib typicky obsahuje knihovny potˇrebn´epro programy z koˇrenov´ehosvazku. Pokud by vˇsechny knihovny byly v /usr/lib a /usr byl samostatn´ysvazek, probl´ems pˇripojen´ım /usr by kompletnˇeochromil cel´ysyst´em,protoˇzeby neˇslospustit nic. Nˇekdyto syst´emy ˇreˇs´ıtak, ˇzekoˇrenov´ysvazek obsahuje sadu z´akladn´ıch program˚u,kter´ejsou staticky slinkovan´e.Napˇr´ıkladFreeBSD m´a takov´ebin´arkyv adres´aˇri /rescue, m´aale i samostatn´eadres´aˇre /lib a /usr/lib. • 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 ˇcastoliˇs´ı.

• hier(7) na FreeBSD a Linuxu popisuje adres´aˇrovou hierarchii tohoto syst´emu, Solaris m´a filesystem(5).

76 Pˇr´ıstupk perifern´ımzaˇr´ızen´ım

• adres´aˇr /dev obsahuje speci´aln´ısoubory zaˇr´ızen´ı.Proces otevˇre speci´aln´ısoubor syst´emov´ymvol´an´ım open() a d´ale komunikuje se zaˇr´ızen´ımpomoc´ıvol´an´ı read(), write(), (), apod. • speci´aln´ısoubory se dˇel´ına – znakov´e . . . data se pˇren´aˇs´ıpˇr´ımomezi 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´ısloovladaˇcev j´adru – vedlejˇs´ı(minor) ˇc´ıslo . . . ˇc´ıslov r´amcijednoho ovladaˇce

• vyrovn´avac´ıpamˇeti (cache) urychluj´ıperifern´ıoperace. Pˇriˇcten´ıse data hle- daj´ınejprve v bufferu. Teprve kdyˇznejsou k dispozici, tak se ˇctou z disku. Pˇri pˇr´ıˇst´ımˇcten´ıstejn´ehobloku jsou data v bufferu. Pˇriz´apisu se data uloˇz´ıdo bufferu. Na disk je syst´empˇrep´ıˇsepozdˇeji.Lze si vynutit i okamˇzit´yz´apisdat na disk. Dnes jiˇzcache typicky nen´ısamostatn´astruktura, vˇseje zastˇreˇseno modulem vitru´aln´ıpamˇeti.

• disky v UNIXu jsou obvykle pˇr´ıstupn´epˇresznakov´e(pouˇz´ıvan´epˇri mkfs – vy- tvoˇren´ısvazku – a fsck – kontrola konzistence) i blokov´erozhran´ı(pouˇz´ıvan´e pˇrinorm´aln´ımprovozu 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´atorsyst´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´adrodetekuje pˇrid´an´ınebo odebr´an´ıhardwarov´ych komponent (viz devfs na stranˇe 74).

• okamˇzit´yz´apisna disk lze vynutit pˇres O DIRECT command ve vol´an´ı fcntl.

77 Fyzick´euloˇzen´ısyst´emu soubor˚u

• syst´emsoubor˚u (svazek, filesystem) lze vytvoˇritna: – odd´ıludisku (partition) – ˇc´astdisku, na jednom disku m˚uˇze b´ytv´ıceodd´ıl˚u – logick´emodd´ılu (logical volume) – takto lze spojit v´ıce odd´ıl˚u,kter´emohou b´yti na nˇekolika disc´ıch, do jednoho svazku. • dalˇs´ımoˇznosti:striping, mirroring, RAID / /home /usr

disk 1 disk 2 disk 3

• v´yrazsyst´emsoubor˚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´ystuppˇr´ıkazu mount) – zp˚usoborganizace 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, ˇzeza sebou n´asleduj´ıc´ıbloky dat se ukl´adaj´ıparalelnˇena r˚uzn´edisky a t´ım se zvyˇsujepˇrenosov´arychlost. • mirroring ukl´ad´akopie dat v´ıcedisk˚upro pˇr´ıpadhav´arienˇekter´ehoz nich.

• paritn´ıdisky: data se ukl´adaj´ına dva disky, na tˇret´ıse ukl´ad´aXOR prvn´ıch dvou, po hav´ariilibovoln´ehodisku 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ˇrebad´atvelk´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´asto zaj´ım´anebo se s t´ımsetk´av´atev praxi, doporuˇcujivaˇs´ıpozor- nosti ZFS, coˇzje filesyst´ema manaˇzerlogick´ych odd´ıl˚uv jednom. Ze Solarisu se jiˇzdostal do FreeBSD od verze 7.0. M˚uˇzete okamˇzitˇezapomenout na jed- notliv´edisky, co je d˚uleˇzit´eje pouze celkov´adiskov´akapacita v syst´emu.

78 Organizace syst´emu soubor˚u s5

blok ˇc. 0 zav´adˇec´ıblok (boot block) 1 superblok 09 12 2 oblast i-uzl˚u(i-nodes) ...

oblast datov´ychblok˚u

• p˚uvodn´ıUNIXov´ysyst´emsoubor˚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´elky512, 1024 nebo 2048 bajt˚u – jedin´y(neduplikovan´y)superblok – datov´yprostor pevnˇerozdˇelen´yna oblast i-uzl˚u a oblast datov´ychblok˚u – pˇrivelikosti bloku 1024 bajt˚ubyla teoretick´avelikost filesyst´emu pˇres 16 GB • boot block – pro uloˇzen´ızavadˇeˇceOSu • superblok – z´akladn´ıinformace o svazku: poˇcetblok˚upro i-uzly, poˇcetblok˚u svazku, seznam voln´ych blok˚u(pokraˇcujeve 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´ıznakmodifikace pouˇz´ıvan´ypro kontrolu korektn´ıho odpojen´ısvazku, ˇcasposledn´ıaktualizace, informace o zaˇr´ızen´ı • i-uzel – typ souboru, pˇr´ıstupov´apr´ava, vlastn´ık,skupina, ˇcasyposledn´ıho pˇr´ıstupu,modifikace dat a modifikace i-uzlu, poˇcetodkaz˚una soubor, velikost souboru, 10 odkaz˚una datov´ebloky a 3 odkazy na nepˇr´ım´ebloky. Pozor na to, ˇzeˇcasvytvoˇren´ısouboru nen´ıuloˇzen. • maxim´aln´ıvelikost souboru: 2113674 blok˚u,tj. pˇribliˇznˇe1 GB pˇri pouˇzit´ı blok˚uvelikosti 512 B

79 • jm´enasoubor˚u– max. 14 znak˚u(14 + 2 = 16, tedy mocnina dvou a tedy bezprobl´emov´euloˇzen´ıadres´aˇrov´ych poloˇzekdo blok˚u)

• pˇripouˇzit´ıtohoto filesyst´emu byla v´ykonnost disk˚uvyuˇzitajen cca na 2% a rychlost ˇcten´ıbyla v ˇr´adujen nˇekolika des´ıtekkilobajt˚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ˇenaaˇzve verzi 4.0 (1988); tato verze z´aroveˇnzavedla diskov´evy- rovn´avac´ıpamˇeti,tedy to, co UNIX m´aod sv´ehovzniku v roce 1970.

Navigace v adres´aˇrov´estruktuˇre

i-nodes /etc/passwd i-node 2 i-node 37 i-node 71

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´emadres´aˇri,jinak zaˇcnev pracovn´ımadres´aˇriprocesu. • koˇrenov´yadres´aˇrm´atypicky ˇc´ıslo2. 0 je pro oznaˇcen´ıpr´azdn´eho uzlu a 1 byla dˇr´ıve pouˇz´ıvan´apro soubor, do kter´ehose vkl´adalyvadn´ebloky, aby je syst´emuˇzd´alenepouˇz´ıval.

• cesta ve kter´eje v´ıcelom´ıtekza sebou je st´aleplatn´a,tj. ///a///b///c je ekvivaletn´ı /a/b/c.

80 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ˇretpouze v r´amcijednoho (logick´eho) filesyst´emu.

• to co “norm´alnˇe” vid´ıtepˇriv´ypisuadres´aˇr˚ujsou vˇetˇsinouhardlinky, takˇze rozdˇelen´ınen´ına soubory, hardlinky a symbolick´elinky. Co se t´yˇcesoubor˚u, jsou pouze hardlinky a symlinky.

hardlink – odkaz na stejn´yi-uzel – vlastnˇedruh´ejm´enosouboru – nen´ırozd´ılmezi origin´alema hardlinkem – lze vytv´aˇretjen v r´amcifilesyst´emu – nelze vytv´aˇretpro adres´aˇre symbolick´ylink (symlink, softlink) – pouze odkaz na skuteˇcnoucestu k souboru jin´ehotypu (ls -l jej oznaˇcuje’l’), tj. symbolick´ylink je typem odliˇsn´yod bˇeˇzn´ehosou- boru a jeho data obsahuj´ıobyˇcejn´yˇretˇezec– jm´enocesty, at’ jiˇz relativn´ınebo absolutn´ı – odliˇsn´echov´an´ıpro origin´ala link (napˇr.pˇrimaz´an´ı) – pozor na relativn´ı a absolutn´ı cesty pˇripˇresouv´an´ı symbolick´eho linku – m˚uˇzeukazovat i na adres´aˇrnebo na neexistuj´ıc´ısoubor

• nejjednoduˇsˇs´ızp˚usobjak si ovˇeˇrit,zda dan´edva linky ukazuj´ına stejn´ysou- bor na disku je pouˇz´ıt -i pˇrep´ınaˇcpˇr´ıkazu ls, kter´yv´amuk´aˇzeˇc´ısloinde- xov´ehouzlu.

81 $ ls -i /etc/passwd 172789 /etc/passwd

Vylepˇsen´ısyst´emu soubor˚u

• c´ıl:sn´ıˇzen´ıfragmentace soubor˚u,omezen´ıpohybu hlav disku um´ıstˇen´ımi-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, menˇs´ıˇc´astido fragment˚ublok˚u • jm´enadlouh´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://mff.devnull.cz/pvu/common/docs/filesystems.ps je porovn´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´ale32-bitov´y,coˇzse odr´aˇzelona maxim´aln´ıd´elcesouboru i na maxim´aln´ıvelikosti filesyst´emu. (Oznaˇcen´ıfile syst´emu jako 32-bitov´ehozna- men´a,ˇzeˇc´ıslai-uzl˚ujsou reprezentov´anajako 32-bitov´a.To pak d´av´ateore- tick´ylimit pro velikost 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´emvyvinut´yv Sun Microsystems, od Sola- risu 10, ted’ jiˇztak´ev FreeBSD 7.

82 V´yvoj ve spr´avˇeadres´aˇrov´ych poloˇzek

• maxim´aln´ıd´elka jm´enasouboru 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´acis adres´aˇriobsahuj´ıc´ıvelk´emnoˇzstv´ı soubor˚u – XFS, JFS, ReiserFS, . . . • UFS2 zav´ad´ızpˇetnˇekompatibiln´ıtzv. dirhash pro zrychlen´ı pˇr´ıstupuk adres´aˇr˚ums velk´ympoˇctem soubor˚u

• dirhash pracuje tak, ˇzepˇriprvn´ımpˇreˇcten´ıadres´aˇrese vytvoˇr´ıv pamˇetihash struktura, n´asledn´epˇr´ıstupy do adres´aˇrejsou pak srovnateln´ese syst´emy pouˇz´ıvaj´ıc´ıB-stromy. T´ımto zp˚usobem je dosaˇzenozlepˇsen´ıbez toho, aby se mˇenilastruktura filesyst´emu na disku. Takov´avylepˇsen´ıale nelze v im- plementaci filesys´emu dˇelat do nekoneˇcna,nakonec je typicky nutn´azmˇena on-disk form´atupro adaptaci na v´ykonostn´ı poˇzadavky (nebo pˇrechod na jin´yfilesyst´em). • mal´esoubory se ˇcasto ukl´adaj´ıv i-nodech, ˇc´ımˇzse uˇsetˇr´ıdalˇs´ıpˇr´ıstupy na disk

83 Virtu´aln´ısyst´emsoubor˚u(Virtual File System)

struct struct struct struct struct file file file file file *file f vnodef vnodef vnodef 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ˇcalipreferovat vzhledem k jeho lepˇs´ımu v´ykonu a nov´ymmoˇznostem,jin´yz˚ust´avali d´aleu s5fs z d˚uvodu zpˇetn´ekom- patibility. To d´aleprohlubovalo probl´emjiˇztak nedostateˇcn´einteroperability mezi r˚uzn´ymiunixov´ymisyst´emy. Nˇekter´ymaplikac´ım nav´ıcplnˇenevyho- voval ani jeden z tˇechto filesyst´em˚u.Postupnˇese tak´eobjevovala potˇreba pracovat s ne-unixov´ymifilesyst´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ˇeloza n´asledekvznik distribuovan´ych filesyst´em˚u– napˇr. NFS (Network File System). • vzhledem k v´yˇsepopsan´esituaci bylo jen ot´azkou ˇcasu,kdy dojde k funda- ment´aln´ımzmˇen´amv infrastruktuˇresyst´emu soubor˚u,aby souˇcasnˇepodpo- roval v´ıcetyp˚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ˇcastose vz´ajemnˇenekompatibiln´ımi ´upravami. VFS se poprv´eobjevilo v roce 1985 v Solarisu 2.0; brzy bylo pˇrevzatoBSD – FFS s podporou VFS se zaˇcalnaz´yvat UFS. • 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´amijiˇzzn´am´esyst´emov´eta- bulce otevˇren´ych soubor˚u.Ta ukazuje na vnode (virtual node). Vnode ob- sahuje ˇc´astnez´avislouna konkr´etn´ımsyst´emu soubor˚ua ˇc´astz´avislou, coˇz m˚uˇzeb´ytnapˇr´ıkladstruktura inode. Ta je specifick´apro kaˇzd´ytyp soubo- rov´ehosyst´emu. Kaˇzd´ytyp filesyst´emu implementuje pevnˇedanou

84 sadu funkc´ıpro jednotliv´eoperace nad soubory, na kterou se odka- zuj´ıvˇsechny virtu´aln´ıuzly odpov´ıdaj´ıc´ıdan´emu typu filesyst´emu. Tato sada funkc´ıtedy definuje vnode interface. Kdyˇztedy zavol´atenapˇr´ıklad open, j´adrozavol´apˇr´ısluˇsnouimplementaci v z´avislostina typu filesyst´emu (napˇr. z modulu ext2fs). Implementaˇcnˇez´avisl´aˇc´aststruktury vnode je pˇr´ıstupn´a pouze z funkc´ıpˇr´ısluˇsn´ehotypu filesyst´emu; j´adrodo n´ıtedy ,,nevid´ı”pˇr´ımo. Jak uvid´ıtena dalˇs´ımslajdu, existuje jeˇstˇejedna sada funkc´ı,kter´ase t´yka pr´aces filesyst´emy jako takov´ymi. Ta pak definuje VFS interface. Tyto dvˇesady spoleˇcnˇe tvoˇ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´ehosyst´emu spec) a prostˇrednictv´ım ukazatele s realvp se odkazuje na re´aln´yvnode pro operace se speci´aln´ımsouborem; ten je potˇrebanapˇr´ıkladpro kontrolu pr´avpˇr´ıstupu.Kaˇzd´emu zaˇr´ızen´ım˚uˇze odpov´ıdatv´ıcespeci´aln´ıch soubor˚u,a tedy v´ıcesnodes 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, to ale nen´ı na obr´azkuzachyceno. Pˇriotevˇren´ı speci´aln´ıhosouboru 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´ıslazaˇ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´ıceviz napˇr´ıklad[Vahalia].

Hierarchie souborov´ych syst´em˚u

vfs mount list struct file rootvfs f vnode v vfspVFSVNODEVFS

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´etn´ımtypu filesyst´emu, tedy podobnˇejako vnode funguje

85 pro soubory. Tato struktura reprezentuje jeden konkr´etn´ıfyzick´yfilesyst´em, aktu´alnˇepˇrimontovan´ydo hierarchie soubor˚u.V tomto v´azan´emseznamu tedy m˚uˇzeb´ytv´ıcestruktur stejn´ehotypu souborov´ehosyst´emu.

• 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´emempodporo- van´etypy filesyst´em˚u,z tabulky se vyb´ır´apˇripˇripojov´an´ısvazku podle typu filesyst´emu zadan´ehopˇrivol´an´ı mount • v vfsp – odkaz z vnode na filesyst´em(strukturu vfs), na kter´emleˇz´ısoubor reprezentovan´ypomoc´ıvnode

• v vfsmountedhere – pouze ve vnode, kter´yreprezentuje mount point (ad- res´aˇr,na kter´emje pˇripojen koˇrenjin´ehofilesyst´emu); odkazuje na strukturu vfs reprezentuj´ıc´ıpˇripojen´yfilesyst´em • v vnodecovered – odkaz na vnode adres´aˇre,na kter´emje filesyst´empˇripojen

Otevˇren´esoubory z pohledu j´adraI.

Per-process File System System Descriptor Tables File Table Inode Table

Process A Count 1 WRONLY

. Count 1 . /etc/group . Count 2 RDONLY Process B

Count 2 Count 4 RDWR /etc/passwd ......

• toto je nejjednoduˇsˇs´ıpohled na tabulky v j´adˇrekter´ese t´ykaj´ısoubor˚u,je to pˇrevzatoz [Bach]; dnes to je o nˇecosloˇzitˇejˇs´ı,myˇslenka je ale poˇr´adstejn´a. Realitˇev´ıcese podobaj´ıc´ıobr´azekje na pˇr´ıˇst´ımslajdu. • kaˇzd´yproces m´asvoji tabulku souborov´ych deskriptor˚u(user file descriptor table)

86 • z t´etotabulky je odkazovn´anona syst´emovou tabulku otevˇren´ych soubor˚u syst´emu (file table; ano, tato tabulka je pouze jedna). Zde je m´odotevˇren´ı souboru a tak´e aktu´aln´ıpozice v souboru.

• z tabulky otevˇren´ych soubor˚uje odkazov´anodo tabulky naˇcten´ych inod˚uv pamˇeti.Dnes jsou to tzv. vnodes – virtual nodes, ale to v t´etochv´ılinen´ı relevantn´ı. • 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´ıletstejnou aktu´aln´ı pozici v souboru.

• pˇriotevˇren´ısouboru pomoc´ıvol´an´ı open se vˇzdyalokuje 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´ahneduplikac´ıdeskriptor˚u,kdy v´ıcedeskriptor˚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´ehoprocesu pomoc´ı vol´an´ı fork(), viz strana 138.

Otevˇren´esoubory z pohledu j´adraII.

struct proc uf next uf next u first u proc struct struct struct struct user ufchunk ufchunk ufchunk

p cred 201...201...201... 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´adropro 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´odsouboru (otevˇrenpro ˇcten´ı, z´apis,atd.), poˇcetdeskriptor˚u,kter´ese na ni odkazuj´ı,ukazatel na vnode a

87 pozici v souboru. Jedno otevˇren´ısouboru m˚uˇzeb´ytsd´ılenov´ıcedeskriptory, jestliˇzebyl 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ˇrelsoubor. • jeden vnode odpov´ıdaj´ıc´ıjednomu souboru m˚uˇzeb´ytsd´ılennˇekolika struk- turami file, pokud byl dan´ysoubor v´ıcekr´atotevˇ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ˇrebapˇristupovat do spustiteln´ehosouboru a proto se alokuje vnode.

Oprava konzistence souborov´ehosyst´emu • pokud nen´ıfilesyst´empˇredzastaven´ımsyst´emu korektnˇe odpojen, mohou b´ytdata v nekonzistentn´ımstavu. • ke kontrole a opravˇesvazku slouˇz´ıpˇr´ıkaz fsck. Postupnˇe testuje moˇzn´enekonzistence: – v´ıcen´asobn´eodkazy na stejn´yblok – odkazy na bloky mimo rozsah datov´eoblasti syst´emu soubor˚u – ˇspatn´ypoˇcetodkaz˚una i-uzly – nespr´avn´avelikost soubor˚ua adres´aˇr˚u – neplatn´yform´ati-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´e(napˇr.XFS v IRIXu, Ext3 v Linuxu) a transakˇcn´ı (ZFS) syst´emy soubor˚unepotˇ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´ymvol´an´ım sync(). Perio- dicky vyrovn´avac´ıpamˇetiukl´ad´azvl´aˇstn´ısyst´emov´yproces (d´emon).

• fsck kontroluje pouze metadata. pokud doˇslok poruˇsedat samotn´ych, ne- pozn´ato, natoˇzaby s t´ımnˇecomohl udˇelat.

• 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

88 ** 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)

Dalˇs´ızp˚usoby zajiˇstˇen´ıkonzistence filesyst´emu

• tradiˇcn´ıUFS – synchronn´ız´apismetadat – aplikace vytv´aˇrej´ıc´ınov´ysoubor ˇcek´ana inicializaci inode na disku; tyto operace pracuj´ırychlost´ıdisku a ne rychlost´ı CPU – asynchronn´ız´apisale ˇcastˇejizp˚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ˇriprobl´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´avislostimezi ukazately na diskov´e struktury a zapisuje data na disk metodou write-back tak, ˇzedata na disku jsou vˇzdykonzistentn´ı – ZFS je nov´yfilesyst´emv Solarisu, kter´ypouˇz´ıv´a copy-on-write transakˇcn´ımodel

• filesystem metadata = inodes, directories, free block maps • ext2 dokonce defaultnˇepouˇz´ıv´aasynchronn´ız´apismetadat a je pˇripouˇz´ıt´ı synchronn´ıhoz´apisuv´yraznˇepomalejˇs´ıneˇzUFS • z´avisl´eoperace jsou napˇr´ıklad smaz´an´ı poloˇzkyz adres´aˇrea smaz´an´ı dis- kov´ehoinode. Pokud by se stalo, ˇzese nejdˇr´ıve smaˇzediskov´yinode a pak te- prve poloˇzka v adres´aˇri,pˇriv´ypadkumezi tˇemitodvˇemioperacemi vnik´ane- konzistence – link ukazuje na diskov´ysoubor, kter´yneexistuje. Nen´ıprobl´em se tomuto vyhnout pˇrisynchronn´ımz´apisumetadat (v´ımekdy a co zapisu- jeme, urˇcujemetedy poˇrad´ız´apisu),ale pˇrimetodˇewrite-back je jiˇznutn´e ˇreˇsitz´avislostijednotliv´ych blok˚una sebe, protoˇzepˇriklasick´esynchronizaci vyrovn´avac´ıch pamˇet´ına disk j´adronezaj´ım´a,kter´yblok se zap´ıˇsedˇr´ıv a kter´ypozdˇeji. • ˇcastojsou bloky na sobˇez´avisl´eve smyˇcce.Soft updates dok´aˇzetakovou smyˇckurozb´ıtt´ım,ˇzeprovede roll-back a po z´apisupak roll-forward • v´ykon soft updates je srovnateln´yv´ykonu UFS filesyst´emu s asynchronn´ım z´apisemmetadat • teoreticky soft updates zaruˇcuj´ı,ˇzepo rebootu nen´ıpotˇrebapouˇz´ıt fsck, tj. ˇzefilesyst´embude v takov´emstavu, ˇzeje moˇzn´enabootovat. Je vˇsaknutn´e

89 pouˇz´ıttzv. background fsck pro opravy nez´avaˇzn´ych chyb – to je povaˇzov´ano st´aleza 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ˇcenjako pouˇzit´y,ale ˇz´adn´ysoubor ho nepouˇz´ıv´a. • soft updates nejsou vˇzdydoporuˇcov´any pro root filesyst´em.Probl´emje to, ˇzeztr´atametadat na root filesyst´emu (viz 30-ti sekundov´aperioda z´apisu) m˚uˇzeb´ytv´yraznˇevˇetˇs´ıhrozbou zde neˇzna /usr, /home atd. Dalˇs´ınev´yhodou m˚uˇzeb´yti to, ˇzeu soft updates mi smaz´an´ıvelk´ehosouboru hned neuvoln´ı m´ısto. • pˇr´ıklad:na bezpeˇcnouoperaci rename potˇrebujupˇrisynchronn´ımz´apisume- tadat 4 z´apisy– zv´yˇsen´ıpoˇctuodkaz˚uv inode, vytvoˇren´ınov´eadres´aˇrov´e poloˇzky, smaz´an´ıstar´e,a opˇetn´esn´ıˇzen´ıpoˇctuodkaz˚uv inode. Kdykoli by syst´emspadnul, nenastane nebezpeˇcn´asituace. Napˇr´ıklad 2 odkazy z ad- res´aˇr˚una inode s referenˇcn´ımpoˇctem1 je probl´em,protoˇzepo zruˇsen´ıjed- noho odkazu to bude vypadat, ˇzesoubor je st´alena disku, kdyˇzuˇzbyla jeho data d´avnosmaz´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´ıkladz´alohu. Opaˇcn´asituace, tj. jeden odkaz na inode s referenc´ı2 sice tak´enen´ıspr´avn´asi- tuace, ale neohroˇzujeto moˇznostfilesyst´emnamontovat a norm´alnˇepouˇz´ıvat. V nejhorˇs´ım se stane, ˇzesoubor vypad´aˇzejiˇzna disku nen´ıa pˇritomst´ale existuje. U soft updates operace rename vytvoˇr´ıkruˇznici,protoˇzenejdˇr´ıve je potˇrebazapsat zv´yˇsen´ıpoˇctureferenc´ı,pak adres´aˇrov´ebloky a pot´esn´ıˇzen´ı referenc´ı.A protoˇzezv´yˇsen´ı/sn´ıˇzen´ıse t´yk´astejn´ehoinode, tak je pˇriz´apisu tˇrebaudˇelatroll-back na (ˇreknˇeme)2, zapsat inode na disk, zapsat bloky adres´ar˚ua pak roll-forward na poˇcetreferenc´ı1. Pˇrit´etoakci je nad inodem drˇzenz´amek,takˇzenikdo nenaˇctestarˇs´ıdata. Je jednoduch´euk´azat, ˇzenelze zapsat ˇz´adn´yz tˇech tˇr´ıblok˚uv kruˇznicitak, jak to je na konci operace re- name, ˇzeje opravdu nutn´yten roll-back – mohli bychom uvaˇzovat, ˇzeinode se vlastnˇenezmˇenila nen´ıtˇrebaˇreˇsitzda se m˚uˇze/nem˚uˇzezapsat; z´apisnov´eho adres´aˇrov´ehoodkazu bez zv´yˇsen´ıpoˇctuodkaz˚uv inodu by n´astotiˇzmohl dostat pˇresnˇedo situace, kter´aje pops´anao p´arˇr´adk˚uv´yˇse.

90 Pˇr´ıstupov´apr´ava vlastn´ık(u) skupina (g) ostatn´ı(o) z }| { z }| { z }| { nejvyˇsˇs´ıbit 4 2 1suid sgid r sticky w x • SGID pro soubor bez pr´ava spuˇstˇen´ıpro skupinu v System V: kontrola z´amk˚upˇrikaˇzd´empˇr´ıstupu(mandatory locking) • sticky bit pro adres´aˇre:pr´avo mazat a pˇrejmenov´avat soubory maj´ıjen vlastn´ıcisoubor˚u • SGID pro adres´aˇr:nov´esoubory budou m´ıtstejnou skupinu jako adres´aˇr(System V; u BSD syst´em˚uto funguje jinak, viz pozn´amky)

• SGID pro adres´aˇreu BSD syst´em˚uzp˚usob´ı,ˇzesoubory a podadres´aˇrevy- tvoˇren´ev tomto adres´aˇribudou m´ıtstejn´ehomajitele jako je majitel dan´eho adres´aˇre.Nutn´ympˇredpokladem je d´aleto, ˇzedan´yUFS filesyst´emmus´ıb´yt namontov´ans suiddir pˇr´ıznakem a v j´adruje option SUIDDIR (a to nen´ı default). Nav´ıcto nefunguje pro roota. Tato moˇznost existuje kv˚uliSambˇea Nettalku.

• sticky bit pro adres´aˇre: pˇrejmenovat nebo smazat soubor m˚uˇzejen jeho vlastn´ık(v nˇekter´ych implementac´ıch staˇc´ıi pr´avo z´apisudo souboru), nesta- ˇc´ıpr´avo z´apisudo adres´aˇre.Toto nastaven´ıse pouˇz´ıv´apro veˇrejn´eadres´aˇre (napˇr. /tmp). • p˚uvodnˇemˇelsticky bit v´yznami pro spustiteln´esoubory: program s nasta- ven´ymsticky bitem z˚ustalpo ukonˇcen´ıv pamˇetia 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 (ACLs), kter´edovoluj´ıjemnˇejˇs´ıpˇridˇelov´an´ıpr´avjednotliv´ymuˇzivatel˚uma skupin´am.

91 API pro soubory

• pˇredpouˇzit´ımmus´ı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´ıcedeskriptor˚um˚uˇzesd´ılet jedno otevˇren´ısouboru (m´odˇcten´ı/z´apis,ukazatel 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´apisz/do souboru: read(), write() • zmˇenapozice: 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ˇzdyvoln´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´ıˇcinnostpouˇz´ıvaj´ıvol´an´ıj´adra(napˇr. open, write, read). My se nebudeme knihovnou stdio zab´yvat.

92 Otevˇren´ısouboru: open()

int open(const char *path, int oflag, ... ); • otevˇresoubor dan´yjm´enem(cestou) path, vr´at´ıˇc´ıslojeho deskriptoru (pouˇzijeprvn´ıvoln´e), oflag je OR-kombinace pˇr´ıznak˚u – O RDONLY/O WRONLY/O RDWR . . . otevˇr´ıtpouze 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ˇsitpˇredchoz´ıobsah (pr´avo z´apisunutn´e) – ... • pˇri O CREAT definuje tˇret´ıparametr mode pˇr´ıstupov´apr´ava

• pˇripouˇzit´ı O CREAT se mode jeˇstˇemodifikuje podle nastaven´ıaktu´aln´ımasky, kter´ese mˇen´ıvol´an´ım umask. Defaultn´ıhodnota je typicky 022. Doporuˇcuji se zamyslet, zda ji ve vaˇsem shell profile skriptu nenastavit na 077. To ale nikdy nedˇelejtepro roota, jinak skonˇc´ıtes podivnˇese chovaj´ıc´ımsyst´emem – nainstalovan´ysoftware nebude moct spustit pod bˇeˇzn´ymuˇzivatelem, to co dˇr´ıve fungovalo fungovat pˇrestaneapod.

• mode nem´adefaultn´ıhodnotu, tj. vezme se to, co je na z´asobn´ıkui kdyˇztento parametr nen´ıpˇr´ıtomen!Pˇr´ıznakyi m´odjsou uloˇzeny v syst´emov´etabulce otevˇren´ych soubor˚u. • pokud se znovu pouˇzijedˇr´ıve vyuˇz´ıvan´apoloˇzka v tabulce deskriptor˚unebo v tabulce otevˇren´ych soubor˚u,vˇsepotˇ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´emuloˇzen´ıdat (synchronized I/O) – O NOCTTY . . . pˇriotv´ır´an´ı termin´aluprocesem, kter´ynem´aˇr´ıdic´ı ter- min´al,se tento termin´alnestane ˇr´ıd´ıc´ımtermin´alemprocesu – O NONBLOCK . . . pokud nelze ˇcten´ınebo z´apisprov´estokamˇzitˇe,vol´an´ı read/write skonˇc´ıs chybou m´ıstozablokov´an´ıprocesu • v pˇr´ıstupov´ych pr´avech se vynuluj´ı ty bity, kter´ejsou nastaven´epomoc´ı umask.

93 • pro ˇcten´ıa z´apisnelze pouˇz´ıt O RDONLY | O WRONLY, protoˇzeimplementace pouˇzily0 pro read-only flag. Norma proto definuje, ˇzeaplikace mus´ıpouˇz´ıt pr´avˇejeden z tˇechto tˇr´ıflag˚u. • je moˇzn´eotevˇr´ıta z´aroveˇnvytvoˇritsoubor pro z´apistak, ˇzejeho m´odz´apis nedovoluje. Pˇripˇr´ıˇst´ım otevˇren´ı souboru se ale jiˇztento m´oduplatn´ı pˇri kontrole pˇr´ıstupua pro z´apisjej otevˇr´ıtnep˚ujde.Pro O TRUNC tak´eplat´ı,ˇze mus´ıtem´ıtpro dan´ysoubor pr´avo z´apisu. • Chov´an´ı O EXCL bez souˇcasn´ehopouˇzit´ı O CREAT nen´ı definov´ano.Pro za- myk´an´ısoubor˚use pouˇz´ıv´a fcntl, viz strana 104.

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´avse 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´ılinebyl otevˇren´ypro proces • open dok´aˇzeotevˇr´ıt regul´arn´ı soubor, zaˇr´ızen´ı i pojmenovanou rouru, ale vytvoˇritdok´aˇzejen regul´arn´ısoubor; pro ostatn´ıtypy soubor˚uje nutn´epouˇz´ıt zde uveden´aspeci´aln´ıvol´an´ı. • Test pomoc´ı pˇr´ıznaku O EXCL na to, zda soubor existuje, a jeho pˇr´ıpadn´e vytvoˇren´ıje atomick´aoperace. Toho se vyuˇz´ıv´apˇripouˇz´ıv´an´ılock soubor˚u. Ze slajdu je vidˇet,ˇzetento test je moˇzn´eprov´estjen pomoc´ıvol´an´ı open, ne creat. • Speci´aln´ısoubory m˚uˇzevytv´aˇretpouze root, protoˇzese pomoc´ınich definuj´ı pˇr´ıstupov´apr´ava k perifern´ımzaˇr´ızen´ım. • Povolen´ehodnoty pro mode je moˇzn´enal´eztvˇetˇsinouv manu´alov´estr´ankce pro chmod(2), a urˇcitˇeje naleznete i v hlaviˇckov´emsouboru stat.h, kde mus´ıb´yt podle normy definovan´e.

94 Cten´ıaˇ z´apissoubor˚u: read(), write()

ssize t read(int fildes, void *buf, size t nbyte ); • z otevˇren´ehosouboru s ˇc´ıslemdeskriptoru fildes pˇreˇcteod aktu´aln´ıpozice max. nbyte bajt˚udat a uloˇz´ıje od adresy buf. • vrac´ıpoˇcetskuteˇ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´ehosouboru s ˇc´ıslemdeskriptoru fildes zap´ıˇsena 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´ımnebo neblokuj´ıc´ımm´odu(flag O NONBLOCK pˇriotevˇren´ısouboru, viz strana 93). • pro obˇevol´an´ıexistuje nˇekolik z´asadn´ıch rohov´ych pˇr´ıpad˚ua n´asleduj´ıc´ıinfor- mace jsou v´yˇnatkem z manu´alov´ych str´anek.Pokud si nejste jisti, doporuˇcuji se pod´ıvat pˇr´ımodo normy (POSIX 1003.1, sekce XSH, ˇc´astSystem Interfa- ces). • 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ˇsenosign´alem, nebo soubor je roura, zaˇr´ızen´ıˇcisoket a aktu´alnˇeje k dispozici m´enˇeneˇz nbyte bajt˚u.Pˇrineexistenci dat se blokuj´ıc´ı read zablokuje, dokud se nˇejak´adata neobjev´ı,neblokuj´ıc´ı read vr´at´ı -1 a nastav´ı errno na EAGAIN. • vol´an´ı write vr´at´ınenulov´ypoˇcetbajt˚umenˇs´ıneˇz nbyte, jestliˇzese do sou- boru nevejde v´ıcdat (napˇr.zaplnˇen´ydisk), z´apisje pˇreruˇsensign´alemnebo 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´yjimkyvzhledem k rour´am jsou uvedeny na stranˇe 98. • 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´odchyby v errno.

95 • pˇreruˇsen´ı read, write sign´alemdˇr´ıv,neˇzse podaˇr´ıpˇreˇc´ıst,resp. zapsat aspoˇn jeden bajt, zp˚usob´ın´avrat s hodnotou -1 a nastaven´ı errno na EINTR. Pozor na to, ˇzezde je rozd´ılproti situaci, kdy pˇreddoruˇcen´ımsign´alupodaˇr´ıpˇreˇc´ıst nebo zapsat alespoˇnjeden bajt (viz v´yˇse). • pˇr´ıznakotevˇren´ısouboru O_APPEND zajist´ıatomick´yz´apisna konec souboru (pouze na lok´aln´ımdisku), tj. kaˇzd´y z´apisse provede na konec souboru (tzv. append-only soubor).

Uzavˇren´ısouboru: close()

int close(int fildes ); • uvoln´ıdeskriptor fildes, pokud to byl posledn´ıdeskriptor, kter´yodkazoval na otevˇren´ısouboru, zavˇresoubor a uvoln´ı z´aznamo otevˇren´ısouboru. • kdyˇzje poˇcetodkaz˚una soubor 0, j´adrouvoln´ı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ˇreposledn´ıproces. • kdyˇzse zavˇreposledn´ıdeskriptor roury, vˇsechna zb´yvaj´ıc´ıdata v rouˇrese zruˇs´ı. • pˇriskonˇcen´ıprocesu se automaticky provede close() na vˇsechny deskriptory.

• Pokud proces potˇrebuje doˇcasn´ysoubor, m˚uˇzeho vytvoˇrit,ihned smazat a pak s n´ım pracovat pˇresexistuj´ıc´ı deskriptor (tento deskriptor lze pˇredat synovsk´ymproces˚um).Kdyˇzje takov´ysoubor zavˇrenvˇsemiprocesy, j´adro smaˇzejeho data z disku.

• I operace close m˚uˇzeselhat. Napˇr.nˇekter´efilesyst´emy zapisuj´ıdata na disk aˇzv okamˇzikuzavˇren´ısouboru, kdyˇzz´apisskonˇc´ıchybou, close vr´at´ı -1. • Chbˇej´ıc´ızav´ır´an´ıdeskriptor˚upˇriukonˇcen´ıpr´aces nimi vede k situaci, kter´ese ˇr´ık´a file descriptor leak. Nen´ıto ´uplnˇepˇresnˇeto, jak se typicky ch´ape memory leak (pamˇet,na kterou jsme ztratili ukazatel), ale n´asledkyjsou podobn´e.

• Pˇr´ıkladna jednoduch´y cat(1) program: read/cat.c

96 Example: copy files

#include #include

int main(int argc, char *argv[]) { char buf[4096]; int inf, outf; ssize t ilen;

inf = open(argv[1], O RDONLY); outf = creat(argv[2], 0666); while ((ilen = read(inf, buf, sizeof (buf))) > 0) write(outf, buf, ilen);

close(inf); close(outf); return (0); }

• Tento pˇr´ıkladje kompletn´ı! Staˇc´ıprov´estcut-and-paste, pˇreloˇzita spustit. Nutno poznamenat, ˇzepro ´uˇcelypouˇzit´ıpouze jednoho slajdu se netestuj´ı ˇz´adn´echyby, vˇcetnˇeignorov´an´ıtoho, ˇzeuˇzivatel m˚uˇzeprogram spustit bez parametr˚u,coˇzzp˚usob´ıpokus o pˇr´ıstupdo pamˇetina m´ısto,kter´eneobsahuje oˇcek´avan´adata. To pak na nˇekter´ych syst´emech m˚uˇzezp˚usobitcore dump.

• Je neefektivn´ıˇc´ısta zapisovat soubor po jednotliv´ych bajtech, protoˇzekaˇzd´e syst´emov´evol´an´ım´ajist´yoverhead, nez´avisl´yna velikosti zpracov´avan´eho bloku. Lepˇs´ıje proto najednou zpracov´avat rozumnˇevelk´ebloky, napˇr´ıklad8- 64KB. Pˇrechoz´ıpˇr´ıklad read/cat.c m´apˇrep´ınaˇc -b pro nastaven´ıvelikosti bloku pro ˇcten´ı;zkuste s (a bez) -b 1 a zmˇeˇrtepomoc´ı time(1). Uvid´ıte velk´yrozd´ıl.

• Pokud potˇrebujetepracovat s mal´ymiˇc´astmi/buffery, je lepˇs´ıpouˇz´ıtstream orintovan´eknihovn´ıfunkce fopen, fread, . . . kter´edata vnitˇrnˇebufferuj´ı. • Vˇsimnˇetesi, ˇzevˇzdyzapisujeme jen tolik bajt˚u,kolik jsme jich naˇcetli.

97 Working with a named pipe (FIFO)

• it may not be possible to create a FIFO on a distributed filesystem (eg. NFS or AFS) • you need to know the semantics of opening a FIFO – opening a FIFO for just reading will block until a writer (aka producer) shows up, unless one already exists. – opening a FIFO for just writing will block until a reader (aka consumer) shows up, unless one already exists. – this behavior can be adjusted using a flag O NONBLOCK • semantics for reading and writing is a bit more complicated, see the notes below this slide. – same as for a conventional, unnamed, pipe (will be later)

• Co se t´yˇcevytvoˇren´ıpojmenovan´eroury, mluv´ımezde o vol´an´ı mkfifo ze strany 94. Pouˇzit´ınepojmenovan´eroury je popsan´ena stranˇe 137. • Cten´aˇrjeˇ proces, kter´yotevˇresoubor (i) pro ˇcten´ı, zapisovatel je proces, kter´yotevˇresoubor (i) pro z´apis.

• Je moˇzn´eotevˇr´ıtrouru pro z´apisi ˇcten´ıstejn´ymprocesem najednou, aniˇzby pˇredt´ımexistoval ˇcten´aˇrnebo zapisovatel. Proces pak m˚uˇzedo roury zapiso- vat a z opaˇcn´ehokonce ˇc´ıst,co do roury napsal. • Pokud rouru nem´aˇz´adn´yproces otevˇrenoupro 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ˇrezablokuje ˇcek´an´ım na zapisovatele. Pozor ale na to, ˇzepokus o ˇcten´ı z roury bez zapisovatele okamˇzitˇevr´at´ı0 jako indikaci konce souboru; proces se nezablokuje ˇcek´an´ım na zapisovatele, bez ohledu na to zda byl soubor otevˇrenv blokovac´ımˇcineblokovac´ımm´odu.Pˇri z´apisu do roury bez ˇcten´aˇre(tj. zapisovatel otevˇrelrouru jeˇstˇev dobˇe,kdy ˇcten´aˇrexistoval, viz n´asleduj´ıc´ıodstavec) poˇslekernel procesu sign´al SIGPIPE (“broken pipe”):

bash$ dd if=/dev/zero | date Sun Mar 2 01:03:38 CET 2008 bash$ echo ${PIPESTATUS[0]} 141 bash$ kill -l 141 PIPE

98 • v pˇr´ıpadˇeotev´ır´an´ıpouze pro z´apiss 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ˇrenebyla data, kter´anebudou v kr´atk´edobˇepˇreˇctena– syst´emnem´a zp˚usob,jak uschov´avat data v rouˇrebez ˇcasov´ehoomezen´ı.Bez O NONBLOCK flagu se proces zablokuje ˇcek´an´ım na ˇcten´aˇre.Asymetri´ı je m´ınˇenoto, ˇze syst´emu nevad´ı ˇcten´aˇri bez zapisovatel˚u,ale nechce m´ıt zapisovatele bez ˇcten´aˇr˚u.I tato situace se m˚uˇzest´at,viz pˇredchoz´ıodstavec, ale tam to jinak ˇreˇsitnelze. • z uveden´ehotedy vypl´yv´a,ˇzepokud chcete vytvoˇritproces, kter´yˇcek´ana po- jmenovan´erouˇrea vykon´av´apoˇzadavky od r˚uzn´ych proces˚u-zapisovatel˚u(od kaˇzd´ehojeden), mus´ıteji otevˇr´ıts flagem O RDWR i kdyˇzdo roury nehodl´ate zapisovat; jinak po prvn´ımzablokov´an´ıv open pˇriˇcek´an´ına otevˇren´ıroury zapisovatelem by dalˇs´ıvol´an´ı read pro akceptov´an´ıdalˇs´ıhopoˇzadavku ty- picky vr´atilo0, pokud by n´ahodou roura nebyla mezit´ımpro z´apisotevˇrena dalˇs´ımprocesem. • z´apismaxim´aln´ıvelikosti PIPE BUF (limits.h) je zaruˇcen´yjako atomick´y,tj. data nesm´ıb´ytproloˇzenadaty jin´ych zapisuj´ıc´ıch proces˚u.Napˇr.v Solarisu 11 to je to 5120 bajt˚u,ve FreeBSD 5.4 je to 512 bajt˚u.Pokud zapisujete v´ıce,m˚uˇzese to st´at.Z´aroveˇnplat´ı,ˇzepokud se zapisuje m´enˇeneˇz PIPE BUF bajt˚u,zap´ıˇsouse vˇzdynajednou, a pokud je nastaveno O NONBLOCK a nelze toho dos´ahnout,vr´at´ıse chyba. • roura nem´apozici v souboru, z´apistak vˇzdypˇrid´av´ana konec. • stejnˇese vzhledem ke ˇcten´ıa z´apisuchov´ai nepojmenovan´aroura, viz strana 137.

Setting file position: lseek()

off t lseek(int fildes, off t offset, int whence ); • will reposition the file offset for reading and writing in an already opened file associated with a file descriptor fildes

• based on value of whence, the file offset is set to: – SEEK SET . . . the value of offset – SEEK CUR . . . current position plus offset – SEEK END . . . size of the file plus offset • returns the resulting offset (ie. from the file beginning)

• lseek(fildes, 0, SEEK CUR) only returns the current file position

99 • Poˇc´ıt´ase od 0, tj. offset 0 je prvn´ıbajt souboru. Tam, kde to m´asmysl, je moˇzn´epro offset pouˇz´ıti z´aporn´eˇc´ıslo.Pˇr´ıklad: read/lseek.c . • Lze se pˇresunouti na pozici za koncem souboru. Pokud se pak provede z´apis, soubor se prodlouˇz´ıa v pˇreskoˇcen´eˇc´astibudou sam´enuly (samotn´e lseek nestaˇc´ı).Nˇekter´efilesyst´emy takov´ebloky cel´ych nul pro ´usporu m´ıstane- 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ˇripouˇzit´ı lseek se ˇz´adn´eI/O neprovede, tj. ˇz´adn´ypˇr´ıkaz se nepoˇslena ˇradiˇcdisku.

• lseek nemus´ıslouˇzitjen pro operace read a write, ale tak´epro n´aslednou operaci lseek

• Seekov´an´ıa z´apism˚uˇzev´estk probl´em˚umse z´alohami.Pˇr´ıklad: read/big-file.c demonstruje, ˇzepˇresun souboru s ”d´ırami”(tzv. sparse file) m˚uˇzev´estk n´ar˚ustuvelikosti souboru co se t´yˇceblok˚ualokovan´ych file syst´emem.Chov´an´ı z´aleˇz´ına kombinaci operaˇcn´ıhosyst´emu, archivn´ıhoprogramu a file syst´emu (a jejich verz´ı).Nˇekter´eprogramy maj´ıpˇrep´ınaˇce,kter´eumoˇzn´ıd´ıry zachovat (napˇr. dd s conv=sparse, tar s -S, rsync s --sparse, atd.). • Pozor na pˇrehozen´ıparametr˚u.Druh´aˇr´adka samostatnˇevypad´aOK, ale m´a pˇrehozen´eparametry. SEEK SET je nav´ıc0 a SEEK CUR je 1, takˇze v´asto nikam neposune a nic ˇspatn´ehose nestane, a o to je horˇs´ıto pak naj´ıt.

lseek(fd, 1, SEEK_SET) lseek(fd, SEEK_SET, 1)

100 Change file size: truncate()

int truncate(const char *path, off t length ); int ftruncate(int fildes, off t length ); • causes the regular file to be truncated to a size of precisely length bytes. • if the file was larger than length, the extra data is lost • if the file previously was shorter, it is extended, and the extended part reads as null bytes

• zruˇsitveˇsker´yobsah souboru pˇriotevˇren´ıse d´apˇr´ıznakem O TRUNC ve funkci open. • podrobnosti je tˇrebahledat v manu´alov´estr´ance,napˇr.ve FreeBSD v sekci BUGS nalezneme toto: Use of truncate to extend a file is not portable.

101 Descriptor duplication: dup(), dup2()

int dup(int fildes ); • creates a copy of the file descriptor fildes, using the lowest-numbered unused descriptor. Returns the new descriptor.

• same as fcntl(fildes, F DUPFD, 0); (will be later) int dup2(int fildes, int fildes2 ); • duplicates fildes to fildes2. • same as close(fildes2); fcntl(fildes, F DUPFD, fildes2);

• prvn´ıvoln´ydeskriptor se pouˇzijei u otev´ır´an´ıa vytv´aˇren´ısoubor˚u,viz strany 93a 94. • 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, tak se neprovede close(fildes2) a dup2 rovnou vr´at´ı fildes2. V´ıceviz POSIX 1003.1 (ˇc´astXSH, System interfaces).

102 Example: implement shell redirection

• $ 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);

• note the flag O APPEND used to implement a redirection >>. • Dalˇs´ı pˇr´ıklad pouˇzit´ı dup uvid´ıme, aˇzse budeme zab´yvat rourami. Prvn´ı pˇresmˇerov´an´ı(bez stderr) je v read/redirect.c . Vol´an´ı execl v tomto pˇr´ıkladunahrad´ıaktu´aln´ıobraz bˇeˇz´ıc´ıhoprocesu obrazem programu pˇreda- n´ehojako prvn´ıargument. V´ıceo vol´an´ı execl je na stranˇe 131. • pro pochopen´ıtoho jak funguje pˇresmˇerov´an´ıje dobr´esi nakreslit tabulku deskriptor˚uv ˇcasea kam ”ukazuj´ı”.napˇr.pro druh´ypˇr´ıklad(inici´aln´ıstav, stav po close(1) open("out", ...), koneˇcn´ystav):

+------+ +------+ +------+ | 0 +-> stdin | 0 +-> stdin | 0 +-> stdin +------+ +------+ +------+ | 1 +-> stdout ===> | 1 +-> "out" ===> | 1 +-> "out" +------+ +------+ +------+ ^ | 2 +-> stderr | 2 +-> stderr | 2 +----/ +------+ +------+ +------+

• Je potˇrebasi d´atpozor na stav deskriptor˚u.Druh´ypˇr´ıkladnebude 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´ehodeskriptoru). Moˇzn´eˇreˇsen´ı:

close(1); if((fd = open("out", O WRONLY | O CREAT | O TRUNC, 0666)) == 0) dup(0);

103 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);

Manipulate file descriptors and devices: fcntl(), ioctl()

int fcntl(int fildes, int cmd, ...); • provides file descriptor duplication, setting descriptor and file status flags, and advisory and possibly mandatory locking. Example: close standard error output on program execution (exec call) fcntl(2, F SETFD, FD CLOEXEC); int ioctl(int fildes, int request, ... ); • manipulates the underlying device parameters of special files • used as a universal interface for manipulating devices. Each device defines a set of requests it understands.

• jak pozdˇejiuvid´ıme,i k socket˚umse pˇristupujepˇressouborov´edeskriptory, a je tedy moˇzn´e fnctl pouˇz´ıt i na nˇe,tˇrebapro nastaven´ı neblokuj´ıc´ıho socketu. V´ıceinformac´ıviz strana 192.

• 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

104 – F GETFL . . . zjiˇstˇen´ım´oduˇcten´ı/z´apisa 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´ıznakypro RO/RW a ani pˇr´ıznakypro vytvoˇren´ı, zkr´acen´ınebo exkluzivn´ıpˇr´ıstupk sou- boru. – F GETLK, F SETLK, F SETLKW . . . nastavov´an´ız´amk˚u • je d˚uleˇzit´esi uvˇedomit,ˇzejsou dva druhy pˇr´ıznak˚u– pˇr´ıznak(y)pro sou- borov´ydeskriptor a pˇr´ıznaky pro jedno konkr´etn´ı otevˇren´ı souboru – tj. pˇr´ıznakyjsou uloˇzen´eve dvou r˚uzn´ych tabulk´ach.

• perifern´ızaˇr´ızen´ıpodporuj´ıˇcten´ıa z´apisdat 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ˇrinastavov´an´ı pˇr´ıznak˚unejdˇr´ıv vˇzdyzjistˇete, jak´ebyly pˇredt´ım. I kdyˇz jste si jisti, ˇzev dan´echv´ılijsou nulov´ea je tedy moˇzn´eprov´est fcntl(fd, O APPEND), nem˚uˇzetevˇedˇet,co se m˚uˇzezmˇenit(napˇr´ıklado p´arˇr´adk˚uv´yˇse nˇejak´yflag pˇrid´ate,aniˇzbyste vˇedˇeli,ˇzejste ovlivnˇenik´odemdole). Tedy vˇzdypouˇzijtenapˇr´ıkladtoto:

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´ıstotoho je tˇrebapouˇz´ıtbitov´ehojedniˇckov´ehodoplˇnkupˇr´ısluˇsn´eho flagu (flags & ~O APPEND).

105 Get file status information: stat()

int stat(const char *path, struct stat *buf ); int fstat(int fildes, struct stat *buf ); • for a file specified by a path or a file descriptor, returns a struct containing file information, such as: – st ino . . . i-node number – st dev . . . ID of device containing file – st uid, st gid . . . user/group ID of owner – st mode . . . file type and mode – st size, st blksize, st blocks . . . total size in bytes, preferred blocksize for filesystem I/O, and number of 512B blocks allocated – st atime, st mtime, st ctime . . . time of last access, last modification, and last i-node modification – st nlink . . . number of hard links

• update ˇcasuposledn´ıho pˇr´ıstupuk souboru lze na bˇeˇzn´ych file syst´emech vy- pnout pomoc´ıoptionu noatime pˇr´ıkazu mount. Hodit se to m˚uˇzepro urych- len´ı,pokud se prov´ad´ıˇcten´ıvelk´ehomnoˇzstv´ısoubor˚ua nez´aleˇz´ına ˇcasu pˇr´ıstupuna tˇechto souborech (napˇr.pˇrikompilaci). • Metadata jsou informace o souboru – tedy m´od,ˇcasypˇ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ˇzenov r´amcidan´ehosouboru, ale v adres´aˇriˇciv 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´amflagy deskriptoru ani flagy z pole tabulky otevˇren´ych soubor˚uv syst´emu, zde jde o informace ohlednˇesouboru uloˇzen´ehona pamˇe- t’ov´emm´ediu.

• Co se stane kdyˇzse zavol´a fstat na deskriptory 0,1,2 ? (pˇredpokl´ad´ameˇze nejsou pˇresmˇerovan´ez norm´aln´ıhostavu)

• st ctime nen´ıˇcasvytvoˇren´ısouboru (creation time), ale ˇcaszmˇeny inde- xov´ehouzlu (change time) • Norma nespecifikuje poˇrad´ıpoloˇzekve struktuˇreani nezakazuje pˇridatdalˇs´ı.

• Pˇr´ıklad: stat/stat.c

106 Get file status information (2)

• for a file type, in there are constants S_IFMT (bit mask for the file type bit field), S_IFBLK (block device), S_IFCHR (character device), S_IFIFO (FIFO), S_IFREG (regular), S_IFDIR (directory), S_IFLNK (symlink). • macros for file type checking: S_ISBLK(m), S_ISCHR(m), S_ISFIFO(m), S_ISREG(m), S_ISDIR(m), and S_ISLNK(m). • access right masks: S_IRUSR (owner has read permission), S_IWGRP (group has write permission), etc. int lstat(const char *path, struct stat *buf ); • if path is a symlink, stat() returns informace on the file the symlink refers to. This function returns information about the link itself.

• typ a pr´ava souboru jsou uloˇzena spoleˇcnˇev st_mode, proto existuj´ızmiˇno- van´amakra. • S IFMT specifikuje tu ˇc´astbit˚u,kter´ejsou vˇenovan´etypu souboru, makra pro jednotliv´etypy pak nejsou masky, ale hodnoty, takˇzetest na typ souboru je nutn´eudˇelattakto: (st mode & S IFMT == S IFREG). Vˇsechna makra jsou v normˇe,takˇzejejich pouˇz´ıv´an´ımzaruˇc´ımepˇrenositeln´yk´od.

• Pˇr´ıklad: stat/filetype.c

107 Setting file times

int utime(const char *path, const struct utimbuf *times ); • changes file last access and modification times • cannot change i-node access time (ctime) • calling process must have write permission for the file

• Tuto funkci pouˇz´ıvaj´ıhlavnˇekop´ırovac´ıa archivaˇcn´ıprogramy, aby zajistily stejn´eˇcasykopie a origin´alu (napˇr. tar nebo rsync). • Shellov´erozhran´ıpro funkci utime pˇredstavuje pˇr´ıkaz touch. Mˇenittakto ˇcasmodifikace i-uzlu ale nelze.

108 Check permissions for access: access()

int access(const char *path, int amode ); • checks whether the calling process can access the file path • amode is an OR-combination of contants – R_OK . . . read permission test – W_OK . . . write permission test – X_OK . . . execution permission test – F_OK . . . file existence test • in contrast to stat(), the result depends on the process’s RUID and RGID • never use this call, it cannot be used in a safe way. See below.

• Vol´an´ı access aplikuje mechanismus testov´an´ıpˇr´ıstupov´ych pr´avk zadan´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ˇelza norm´aln´ıch okolnost´ık pˇr´ısluˇsn´emu sou- boru pˇr´ıstup.Z toho vypl´yv´a,ˇzetoto vol´an´ıje security hole – mezi testem a n´aslednouakc´ıse soubor m˚uˇzezmˇenittˇrebatak, ˇzep˚uvodn´ı(m˚uj)sou- bor smaˇzua vytvoˇr´ım symbolick´ylink se stejn´ymjm´enemna soubor, ke kter´emu bych jinak nemˇelpˇr´ıstup. Toto proces nem˚uˇzenikdy oˇsetˇrit,takˇze vesele zmodifikuje soubor, kter´ybych jako uˇzivatel nikdy nemohl zmˇenit. Spr´avn´ymˇreˇsen´ımje vr´atitse zp´atkyk re´aln´ymUID/GID a pˇr´ıstup rovnou vyzkouˇset.Pokud napˇr´ıkladdan´ysoubor otevˇreme,uˇzn´amho nikdo pod rukama “nevymˇen´ı”.

109 Setting file permissions

int chmod(const char *path, mode t mode ); • changes permissions of file path to mode. • can be used by the file owner or root

int chown(const char *path, uid t owner, gid t group ); • changes file owner and group for path. Value of -1 means do not change that ID. • only root change change owners so that users could not work around quotas to disown their files • a regular user can change a group of files he/she owns, and must belong to the target group

• 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ˇenitm´odani u souboru s nastaven´ympˇr´ıstupem rw-rw-rw- • v nˇekter´ych implementac´ıch m˚uˇzevlastn´ık souboru pˇredatvlastnictv´ı nˇe- komu 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)

110 File name manipulations

int link(const char *path1, const char *path2 ); • creates a new link (aka hard link), ie. a directory entry, named path2 to file path1. Hard links cannot span filesystems (use symlink for that). int unlink(const char *path ); • deletes a name (ie. a directory entry) and after deleting the last link to the file and after closing the file by all processes, delete the file data. int rename(const char *old, const char *new ); • change the file name (ie. one specific link) from old to new. Works within the same filesystem only.

• opˇetzd˚urazˇnuji,ˇze unix nem´avol´an´ıtypu delete na soubory. Podrob- nˇejiviz strana 69.

• vol´an´ı link vytv´aˇr´ıhardlinky, tj. zobrazen´ıze jm´enasouboru na ˇc´ısloi-uzlu. C´ıslai-uzl˚ujsouˇ jednoznaˇcn´apouze v r´amcisvazku, proto pro linky mezi filesyst´emy je nutn´epouˇz´ıtsymlinky.

• 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´amcijednoho svazku. Pˇresunsouboru mezi filesyst´emy vyˇzadujenejprve soubor zkop´ırovat a pak smazat origin´alvol´an´ım unlink. • rename funguje nad symlinky, ne nad soubory, na kter´esymlink ukazuje • existuje i vol´an´ı remove, viz strana 114.

111 Symbolic links

int symlink(const char *path1, const char *path2 ); • make a new symbolic name from path2 → path1. • path1 may span filesystems, and may not exist at all

int readlink(const char *path, char *buf, size t bufsz ); • put maximum of bufsz bytes from the symlink target path to buf • returns the number of bytes written to buf.

• buf is not terminated by ’\0’

• Shellov´ypˇr´ıkaz ln vol´a symlink nebo link, podle toho, jestli je pouˇzitpˇre- p´ınaˇc -s nebo ne. • Smaz´an´ıhardlinku nesmaˇze soubor, pokud na nˇejvede jeˇstˇejin´yhardlink. Naopak soubor (poloˇzku adres´aˇrei 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’

112 Working with directories

int mkdir(const char *path, mode t mode ); • attempts to create an empty directory path with entries ’.’ a ’..’ int rmdir(const char *path ); • deletes directory path. The directory must be empty. DIR *opendir(const char *dirname ); struct dirent *readdir(DIR *dirp ); int closedir(DIR *dirp ); • sequentially reads directory entries • structure dirent contains: – d_ino . . . i-node number – d_name . . . file name

• Poloˇzkyadres´aˇrenejsou nijak uspoˇr´ad´any, readdir je m˚uˇzevracet v libo- voln´empoˇrad´ı.V pˇr´ıpadˇechyby se vrac´ıNULL jako pˇredt´ıma errno je na- staveno. Konec adres´aˇrese signalizuje t´ım,ˇze readdir vr´at´ıNULL a errno nen´ızmˇenˇeno.

• readdir je stavov´afunkce. Pro vr´acen´ıse na zaˇc´atekje moˇzn´epouˇz´ıtfunkci rewinddir. Pokud tuto funkci vol´atez v´ıcevl´aken je nutn´epouˇz´ıvat reent- rantn´ı readdir r, protoˇzestruktura dirent je statick´a. • V nˇekter´ych implementac´ıch (napˇr.FreeBSD) lze adres´aˇrotevˇr´ıtpro ˇcten´ı(ne pro z´apis)jako norm´aln´ısoubor a ˇc´ıstho pomoc´ı read, ale je tˇrebazn´atjeho vnitˇrn´ıorganizaci. Proto je readdir pro zpracov´an´ıobsahu adres´aˇrelepˇs´ı neˇz read, kter´yvrac´ıraw data adres´aˇre.Kromˇetoho, norma nevyˇzaduje, aby adres´aˇrbylo moˇzn´eˇc´ıstfunkc´ı read, Linux to napˇr´ıkladnedovol´ı. • d ino nen´ımoc uˇziteˇcn´e,protoˇzev 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´ehofilesyst´emu

• Nˇekter´esyst´emy maj´ıve struktuˇre dirent poloˇzku d type. Ta m˚uˇzenab´yvat hodnot DT REG, DT DIR, DT FIFO atd., viz manu´alov´astr´anka pro dirent. Byla to vˇecspecifick´apro BSD a n´aslednˇepˇrevzat´ai jin´ymisyst´emy, napˇr´ı- klad Linuxem. Nen´ıto souˇc´ast´ınormy a tedy to nen´ıpˇrenositeln´e. Pˇreno- siteln´yzp˚usobje na kaˇzdoupoloˇzkuzavolat stat.

• rmdir nefunguje na nepr´azdn´yadres´aˇr,mus´ıtesami smazat jeho obsah pˇred smaz´an´ımadres´aˇre.Nˇekdylze v k´odunal´eztzoufal´epokusy typu system("rm

113 -r xxx") coˇzm´asvoje nev´yhody (napˇr.z´avislostprogramu na shellu. D´ale pozor na sanitizaci promˇenn´ych prostˇred´ıa jm´enaadres´aˇre).

• Norma specifikuje i vol´an´ı remove, kter´ese chov´ajako unlink pro regul´arn´ı soubory, a jako rmdir pro adres´aˇre.

Example: read a directory

int main(int argc, char *argv[]) { DIR *d; struct dirent *de;

for(int i = 1; i < argc; i++) { d = opendir(argv[i]); while(de = readdir(d)) printf("%s\n", de->d_name); closedir(d); } return (0); }

• pˇr´ıkaz ls je zaloˇzenna takov´eto smyˇcce,nav´ıcprov´ad´ınapˇr.tˇr´ıdˇen´ıjmen soubor˚ua zjiˇst’ov´an´ıdalˇs´ıch informac´ıpomoc´ı stat. • konec adres´aˇrese pozn´atak, ˇze readdir vr´at´ı NULL. To vˇsakvr´at´ıi v pˇr´ıpadˇe, pokud nastala chyba. V takov´empˇr´ıpadˇeje k´odchyby v promˇenn´e errno, v pˇr´ıpadˇeprvn´ımje errno nezmˇenˇena.Proto by errno mˇelob´ytvˇzdyna- staven´ena nulu pˇredvol´an´ım readdir. V pˇr´ıkladutomu tak nen´ı,protoˇzez d˚uvodu m´alom´ıstanekontrolujeme errno v˚ubec.

• pˇr´ıklad: readdir/readdir.c

114 Change working directory

• every process has its current working directory. When a process refers to a file using a relative path, the reference is interpreted relative to the current working directory of the process. • the working directory is inherited from the process parent

int chdir(const char *path ); int fchdir(int fildes ); • changes working directory for the process

char *getcwd(char *buf, size t size ); • stores the absolute path to the current working directory to buf, its size must be at least one byte longer than the path length.

• funkci fchdir se pˇred´av´adeskriptor z´ıskan´yvol´an´ım open na adres´aˇr. • funkce getcwd m˚uˇzevr´atitjinou cestu neˇztu, po kter´ejsme se do aktu´aln´ıho adres´aˇredostali, jesliˇzeˇc´astcesty v chdir byl symlink nebo doˇslok pˇresunu (pˇrejmenov´an´ı)nˇekter´ehoadres´aˇrena cestˇeod koˇrene.U souˇcasn´ych unix˚u by se to ale uˇzst´atnemˇelo.

• na vˇetˇsinˇemodern´ıch unixov´ych syst´em˚uexistuje funkce chroot, kter´aumoˇz- ˇnujezmˇenitkoˇrenov´yadres´aˇrvolaj´ıc´ıhoprocesu na dan´yadres´aˇr.Je ˇcasto pouˇz´ıvan´av implementac´ıserver˚uk omezen´ıpˇr´ıstupupouze na dan´ypod- strom file syst´emu (napˇr.FTP servery). Pokud se pouˇz´ıv´apro zapezpeˇcen´ı, vyˇzadujeto zvl´aˇstn´ıopatrnost, protoˇzeexistuj´ıcesty jak se dostat do p˚uvod- n´ıhostromu. Pokud je nutn´ez chroot prostˇred´ıspouˇstˇetprogramy, nast´avaj´ı dalˇs´ı komplikace s nutnost´ı replikace kritick´ych syst´emov´ych soubor˚udo chroot prostˇred´ı(pokud nen´ıprogram upraven aby mˇelvˇsezabudovan´ev sobˇe).Tato funkce nen´ısouˇc´ast´ıaktu´aln´ıverze standardu (POSIX 1003.1- 2008).

– dalˇs´ı,mnohem obecnˇejˇs´ı,zp˚usoby izolace proces˚use daj´ınal´eztv uni- xov´ych syst´emech (jails v FreeBSD, zones v Solarisu, sandboxing v Mac OS X). Zpravidla se velmi liˇs´ıt´ımjak´ehranice dok´aˇz´ıvytyˇcit,k ˇcemu jsou urˇceny, zp˚usobem administrace, . . . .

115 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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

116 Pamˇet’ procesu v uˇzivatelsk´emreˇzimu

text   data   bss     adresovateln´e uˇziv.programem         nelze adresovat z´asobn´ık { oblast user uˇziv.programem

• kaˇzd´yproces m´atˇriz´akladn´ısegmenty (pamˇet’ov´esegmenty, nemluv´ımeo hardwarov´ych segmentech): – text . . . k´odprogramu – data . . . inicializovan´epromˇenn´e – z´asobn´ık

• sekce text a data jsou uloˇzeny ve spustiteln´emsouboru • sekce pro inicializovan´ei neinicializovan´epromˇenn´ea heap jsou br´any dohro- mady jako data

• d´alelze do adresov´ehoprostoru pˇripojit segmenty sd´ılen´epamˇeti(shmat) nebo soubory (mmap). • text je sd´ılen vˇsemiprocesy, kter´eprov´ad´ı stejn´yk´od.Datov´ysegment a z´asobn´ıkjsou priv´atn´ıpro kaˇzd´yproces. • kaˇzd´ysyst´emm˚uˇzepouˇz´ıvat zcela jin´erozdˇelen´ıadresov´ehoprostoru pro- cesu (a typicky tomu tak je). Konkr´etn´ıpˇr´ıkladje na n´asleduj´ıc´ımslajdu, a zobrazuje i sekce pro mmap a heap. • 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, bss a heap (nen´ına obr´azku)dohromady datov´esegmenty procesu. Velikost heapu lze mˇenitpomoc´ısyst´emov´ych vol´an´ı brk a sbrk.

117 • pozn´amka – neinicializovan´epromˇenn´ejsou statick´epromˇenn´e,kter´e(pˇrekva- pivˇe)nejsou inicializovan´e– tj. glob´aln´ıpromˇenn´enebo promˇenn´edefinovan´e jako static ve funkc´ıch i mimo funkce. Jak v´ıtez pˇredn´aˇseko jazyku C, vˇsechny tyto promˇenn´ejsou pˇristartu programu automaticky inicializovan´e nulami. Proto nen´ınutn´em´ıtjejich hodnotu v bin´arce.Jakmile ale nˇejakou z takov´ych promˇenn´ych inicializujete, bude jiˇzsouˇc´ast´ıdatov´ehosegmentu programu na disku. • (uˇzivatelsk´y)z´asobn´ık . . . lok´aln´ınestatick´epromˇenn´e,parametry funkc´ı(na urˇcit´ych architektur´ach v dan´ych modech - 32-bit x86), n´avratov´eadresy. Kaˇzd´yproces m´adva z´asobn´ıky, jeden pro uˇzivatelsk´yreˇzima jeden pro reˇzimj´adra.Uˇzivatelsk´yz´asobn´ıkprocesu automaticky roste podle potˇreby (neplat´ı,pokud se pouˇz´ıvaj´ıvl´akna,tam m´anav´ıckaˇzd´evl´aknoz´asobn´ık sv˚uj).

• oblast user (u-area) . . . obsahuje informace o procesu pouˇz´ıvan´ej´adrem,kter´e nejsou potˇrebn´e, kdyˇzje proces odloˇzenna disku (poˇcetotevˇren´ych soubor˚u, nastaven´ıoˇsetˇren´ısign´al˚u,poˇcetsegment˚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ˇzdyvid´ıpr´avˇejednu u-oblast patˇr´ıc´ıpr´avˇebˇeˇz´ıc´ımu procesu. Dalˇs´ıinformace o procesu, kter´ej´adrom˚uˇzepotˇ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´alerezidentn´ıv pamˇetia viditeln´e v reˇzimu j´adra.

Pˇr´ıklad:Solaris 11 x86 32-bit

• z obr´azkulze vyˇc´ıstnˇekolik dalˇs´ıch vˇec´ı:

118 – maxim´aln´ıvelikost kernelu pro Solaris 11 x86 32-bit je 256 megabajt˚u – mezi namapov´an´ımkernelu a pamˇet´ıvyhrazenou pro mmap je voln´em´ısto – z´asobn´ıkroste smˇeremk niˇzˇs´ımadres´ama jeho velikost je omezena na 128 megabajt˚u

• heap je ˇc´astpamˇeti,kterou si proces m˚uˇzezvˇetˇsovat pomoc´ıvol´an´ı brk a sbrk, a je ˇcastopouˇz´ıvan´afunkc´ı malloc. Funguje to tak, ˇze malloc si po- stupnˇezvˇetˇsujeheap podle potˇreby, a pˇriˇrazenoupamˇet’ internˇespravuje a pˇridˇelujeji procesu po ˇc´astech. Kdyˇztedy vol´ate free, neznamen´ato, ˇze vrac´ıtepamˇet’ syst´emu, ale pouze intern´ımu alok´atoru.

• oblast pro mmap se pouˇz´ıv´apro mapov´an´ısoubor˚u,tedy i sd´ılen´ych knihoven. Nˇekter´ealok´atorypouˇz´ıvaj´ıinternˇei tuto pamˇet’, napˇr´ıkladpro vˇetˇs´ıkusy pamˇetiˇz´adan´enajednou. Je moˇzn´eexkluzivnˇepouˇz´ıvat pouze mmap, pro apli- kaci je to zcela transparentn´ı.Pˇripouˇzit´ı mmap je moˇzn´epamˇet’ syst´emu vracet (vol´an´ım munmap), na rozd´ılod implementace pomoc´ı brk/sbrk. • obr´azekbyl pˇrevzatz [McDougall-Mauro], a nen´ına nˇemoblast pro neini- cializovan´epromˇenn´e.Pokud si ale na tomto syst´emu nech´atevypsat ad- resu jedn´ez nich, zjist´ıte,ˇzeinicializovan´ei neinicializovan´epromˇenn´esd´ıl´ı spoleˇcn´ydatov´ysegment, na obr´azkuoznaˇcen´yjako ,,executable – DATA”. Pˇr´ıklad: pmap/proc-addr-space.c

• mapov´an´ıkernelu nen´ınutn´e,napˇr´ıkladu Solarisu na amd64 architektuˇre (tj. 64-bit) uˇzkernel do uˇzivatelsk´ehoprostoru procesu mapov´annen´ı.

• brk ani sbrk nejsou souˇc´ast´ı normy, pˇrenositeln´eaplikace by proto mˇely pouˇz´ıvat, pokud podobnou funkcionalitu potˇrebuj´ı,vol´an´ı mmap, viz strana 140.

119 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´ıhoprocesu

extern struct user u; z´asobn´ıkj´adra

• proces se dostane do reˇzimu j´adrabud’ pˇr´ıchodem pˇreruˇsen´ıvyvolan´ehoproce- sorem (v´ypadekstr´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´ıhopˇreruˇsen´ı(standardn´ıknihovna takto pˇred´av´a ˇr´ızen´ıj´adru,aby obslouˇzilo syst´emov´evol´an´ı).

• v pamˇetije pouze jedna kopie k´odua dat j´adra,sd´ılen´avˇsemiprocesy. K´od j´adraje vˇzdycel´yrezidentn´ıv pamˇeti,nen´ıodkl´ad´anna disk. • text j´adra . . . k´odj´adraoperaˇcn´ıhosyst´emu, zaveden´ypˇristartu syst´emu a rezidentn´ıv pamˇetipo celou dobu bˇehu syst´emu. Nˇekter´eimplementace umoˇzˇnuj´ıpˇrid´avat funkˇcn´ımoduly do j´adraza bˇehu (napˇr.pˇripˇrid´an´ınov´eho zaˇr´ızen´ıse do j´adradynamicky pˇrid´anov´yovladaˇc),nen´ıproto tˇrebakv˚uli kaˇzd´ezmˇenˇeregenerovat j´adroa 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´ıhoprocesu. • z´asobn´ıkj´adra . . . samostatn´ypro kaˇzd´yproces, je pr´azdn´y,jestliˇzeje proces v uˇzivatelsk´emreˇzimu (a tedy pouˇz´ıv´auˇzivatelsk´yz´asobn´ık).

120 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

• takto vypad´avˇetˇsinoureprezentace pamˇet’ov´ych segment˚uprocesu v j´adˇre. • z´akladn´ımrysem t´etoarchitektury je tzv. memory object, coˇzje abstrakce mapov´an´ımezi kusem pamˇetia m´ıstem,kde jsou data norm´alnˇeuloˇzena(tzv. backing store nebo data object). Takov´em´ıstouloˇzen´ım˚uˇzeb´ytnapˇr´ıklad swap nebo soubor. Adresov´yprostor procesu je pak mnoˇzinamapov´an´ına r˚uzn´edatov´eobjekty. Existuje i anonymn´ıobjekt, kter´ynem´am´ıstotrval´eho uloˇzen´ı(pouˇz´ıv´ase napˇr´ıkladpro 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´etoarchitektuˇreje zaloˇzenaarchitek- tura viru´aln´ıpamˇetiv SVR4. V´ıceinformac´ı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 (NSWI004 - Operaˇcn´ısyst´emy). • z jak´ych segment˚use skl´ad´apamˇet’ov´yprostor konkr´etn´ıhoprocesu lze zjistit pomoc´ıpˇr´ıkazu pmap(1) (na Solarisu, na NetBSD a v nˇekter´ych Linuxov´ych distribuc´ıch) nebo procmap(1) (v OpenBSD) nebo vmmap(1) v Mac OS X.

121 Virtu´aln´ıpamˇet’

pamˇet’ pamˇet’ pamˇet’ pamˇet’ procesu 1 procesu 2 procesu 3 procesu 4               

         re´aln´a    pamˇet’         

• kaˇzd´yproces vid´ısv˚ujadresov´yprostor jako souvisl´yinterval (virtu´aln´ıch) adres od nuly po nˇejakou maxim´aln´ıhodnotu. Pˇr´ıstupn´ejsou pouze ty adresy, na kter´ych je namapov´annˇekter´ysegment procesu (to je pr´avˇeto mapov´an´ı, o kter´emse mluv´ına pˇredchoz´ımslajdu). • j´adrod´alerozdˇelujepamˇet’ procesu na str´anky. Kaˇzd´astr´anka m´asv´eum´ı- stˇen´ıv r´amcifyzick´epamˇeti.Toto um´ıstˇen´ıje d´anostr´ankovac´ımitabulkami j´adraa str´ankymohou b´ytv r´amc´ıch libovolnˇeprom´ıch´any v˚uˇcijejich poˇrad´ı ve virtu´aln´ıadresov´emprostoru. • pokud nen´ıstr´anka pr´avˇepouˇz´ıv´ana,m˚uˇzeb´yttak´eodloˇzenana disk.

• pamˇet’ov´ymanager j´adrazajiˇst’uje mapov´an´ımezi virtu´aln´ımiadresami po- uˇz´ıvan´ymik´odemuˇzivatelsk´ych proces˚ui j´adra na fyzick´eadresy a naˇcten´ı odloˇzen´ych str´anekz disku pˇriv´ypadkustr´anky.

122 Implementace virtu´aln´ıpamˇeti

• procesy v UNIXu pouˇz´ıvaj´ık pˇr´ıstupudo pamˇetivirtu´aln´ı adresy, kter´ena fyzick´eadresy pˇrev´ad´ıhardware ve spolupr´aci s j´adremsyst´emu. • pˇrinedostatku voln´epamˇetise odkl´adaj´ınepouˇz´ıvan´e´useky pamˇetido odkl´adac´ıoblasti (swap) na disk. • pˇredverz´ıSVR2 se procesem swapper (nyn´ı sched) odkl´adaly cel´eprocesy. • od verze SVR2 se pouˇz´ıv´astr´ankov´an´ına ˇz´adost(demand paging) a copy-on-write. Str´ankyse alokuj´ıaˇzpˇri prvn´ım pouˇzit´ıa priv´atn´ıstr´anky se kop´ıruj´ıpˇriprvn´ımodifikaci. Uvolˇnov´an´ıa odkl´ad´an´ıjednotliv´ych str´anekprov´ad´ıproces pageout, odkl´ad´an´ıcel´ych proces˚unastupuje aˇzpˇrikritick´em nedostatku pamˇeti.

pˇrekladadres: pˇr´ıstupna neplatnou adresu nebo pokus o z´apisdo pamˇetipouze pro ˇcten´ıvyvol´asign´al SIGSEGV. swap: odkl´adac´ıprostor se vytv´aˇr´ına samostatn´emodd´ıludisku, od SVR4 m˚uˇze b´yti v souboru. swapper: proces swapper se snaˇz´ıodloˇzitna disk nˇejak´yproces, kter´ynen´ızam- ˇcenv pamˇeti, a na uvolnˇen´em´ıstozav´estdˇr´ıve odloˇzen´yproces. demand paging: pˇriˇz´adostiprocesu o pamˇet’ se pouze uprav´ıtabulka str´anek. Prvn´ıinstrukce adresuj´ıc´ıobsah str´ankyvyvol´av´yjimku.J´adroji oˇsetˇr´ıt´ım, ˇzealokuje str´anku. copy-on-write: v´ıceproces˚um˚uˇzesd´ıletzapisovatelnou fyzickou str´anku,kter´aje ale logicky priv´atn´ıpro kaˇzd´yproces (tato situace nastane napˇr.po vytvoˇren´ı procesu vol´an´ım fork). Dokud procesy z pamˇetipouze ˇctou,pˇristupuj´ıke sd´ılen´estr´ance.Pokud se proces pokus´ıobsah str´ankyzmˇenit, vyvol´av´yjimku. J´adrozkop´ırujestr´anku,pˇridˇel´ıprocesu kopii, kter´auˇzje priv´atn´ıa proces ji m˚uˇzed´alelibovolnˇemˇenit.Ostatn´ıprocesy pouˇz´ıvaj´ı st´alenezmˇenˇenou p˚uvodn´ıstr´anku. str´ankyk odloˇzen´ıse hledaj´ıalgoritmem NRU (not recently used): kaˇzd´astr´anka m´apˇr´ıznaky referenced a modified, na zaˇc´atkuvynulovan´e.Pˇriprvn´ım pˇr´ıstupuse nastav´ı referenced, pˇrizmˇenˇe modified. Oba pˇr´ıznakyse pe- riodicky nuluj´ı.Pˇrednostnˇese uvolˇnuj´ıstr´anky, kter´enejsou modifikovan´e ani pouˇzit´e.Str´ankyk´oduprogramu a mapovan´ych soubor˚use neukl´adaj´ıdo odkl´adac´ıhoprostoru, ale obnovuj´ıse z pˇr´ısluˇsn´ehosouboru.

123 Stavy procesu

z´anik bˇeˇz´ı † vznik v uˇziv. wait reˇzimu exit m´atoha * kill n´avratpˇreruˇsen´ı (zombie) preempce bˇeˇz´ı v reˇzimu usp´an´ı pˇripraven j´adra sp´ı pˇridˇelen´ı v pamˇeti procesoru v pamˇeti zaveden´ı odloˇzen´ıodloˇzen´ı probuzen´ı pˇripraven sp´ı na disku probuzen´ı na disku

• po ukonˇcen´ıprocesu vol´an´ım exit nebo v reakci na sign´alpˇrech´az´ıproces do stavu m´atoha(zombie), protoˇzej´adrosi mus´ıpamatovat k ˇc´ısluprocesu jeho n´avratovou hodnotu. Cel´apamˇet’ procesu je uvolnˇena,zb´yv´apouze struktura proc. Proces lze definitivnˇezruˇsit,aˇzkdyˇzse jeho rodiˇczept´ana n´avratovou hodnotu vol´an´ımtypu wait. Kdyˇznebude p˚uvodn´ırodiˇck dispozici, provede vol´an´ı wait proces init, kter´ypˇrevzalrodiˇcovstv´ı. • v dneˇsn´ıch UNIXech se obvykle do odkl´adac´ıoblasti na disku (swap area) neodkl´adaj´ıcel´eprocesy, ale jednotliv´estr´ankypamˇeti. • proces je usp´an, kdyˇzo to s´ampoˇz´ad´a,napˇr.zaˇcneˇcekat na dokonˇcen´ıpe- rifern´ıoperace. Preempce je naopak nedobrovoln´eodebr´an´ıprocesoru pl´ano- vaˇcem.

124 Pl´anov´an´ıproces˚u

• preemptivn´ıpl´anov´an´ı – jestliˇzese proces nevzd´aprocesoru (neusp´ıse ˇcek´an´ımna nˇejakou ud´alost),je mu odebr´an procesor po uplynut´ıˇcasov´ehokvanta. • procesy jsou zaˇrazeny do front podle priority, procesor je pˇridˇelenvˇzdyprvn´ımu pˇripraven´emu procesu z fronty, kter´a m´anejvyˇsˇs´ıprioritu. • v SVR4 byly zavedeny prioritn´ıtˇr´ıdya podpora proces˚u re´aln´ehoˇcasu(real-time) s garantovanou maxim´aln´ıdobou odezvy. • na rozd´ılod pˇredchoz´ıch verz´ıznamen´av SVR4 vyˇsˇs´ıˇc´ıslo vyˇsˇs´ıprioritu.

• z´akladempreemptivn´ıho pl´anov´an´ı jsou pravideln´apˇreruˇsen´ı od ˇcasovaˇce, kter´aodeberou procesor bˇeˇz´ıc´ımu procesu a pˇredaj´ıˇr´ızen´ıj´adru (aktivuje se pl´anovaˇcproces˚u). • jin´avarianta je nepreemptivn´ı(kooperativn´ı)pl´anov´an´ı, kdy proces bˇeˇz´ı,do- kud se s´amnevzd´aprocesoru, tj. dokud nezavol´atakovou syst´emovou funkci, kter´apˇrepnekontext na jin´yproces. Nev´yhodou kooperativn´ıhopl´anov´an´ı je, ˇzejeden proces m˚uˇzest´aleblokovat procesor a ostatn´ıprocesy se nikdy nedostanou na ˇradu. • UNIX pouˇz´ıv´apro uˇzivatelsk´eprocesy pouze preemptivn´ıpl´anov´an´ı.

• tradiˇcn´ıUNIXov´e j´adro funguje kooperativn´ımzp˚usobem, tj. proces bˇeˇz´ıc´ı v reˇzimu j´adranen´ıpˇrepl´anov´an,dokud se s´amnevzd´aprocesoru. J´adra modern´ıch UNIX˚ujsou jiˇzpreemtivn´ı – je to hlavnˇekv˚uli real-time syst´em˚um;tam je potˇrebam´ıtmoˇznostbˇeˇz´ıc´ıproces zbavit procesoru okam- ˇzitˇe,neˇcekat na to, aˇzse vr´at´ız reˇzimu j´adranebo se s´amusp´ı.Pozor na at’ to nepletete – UNIX byl od sam´ehozaˇc´atkupreemptivn´ısyst´em,ale jeho j´adrobylo nepreemptivn´ı. • pˇripreemptivn´ımpl´anov´an´ım˚uˇzeb´ytproces kdykoliv pˇreruˇsena ˇr´ızen´ıpˇre- d´anojin´emu procesu. Proces si proto nikdy nem˚uˇzeb´ytjist´y,ˇzeurˇcitou operaci (v´ıceneˇzjednu intstrukci, kromˇesyst´emov´ych vol´an´ıse zaruˇcenou atomiˇcnost´ı) provede atomicky, bez ovlivnˇen´ı ostatn´ımi procesy. Pokud je tˇrebazajistit atomiˇcnostnˇejak´eakce, mus´ıse procesy navz´ajem synchronizo- vat. Pˇrikooperativn´ımpl´anov´an´ıprobl´emsynchronizace odpad´a(atomick´a posloupnost operac´ıse zajist´ıt´ım,ˇzese proces bˇehemn´ınevzd´aprocesoru).

125 Prioritn´ıtˇr´ıdy

• syst´emov´a – priorita 60 aˇz99 – rezervov´ana pro syst´emov´eprocesy (pageout, sched,...) – pevn´apriorita • real-time – priorita 100 aˇz159 – pevn´apriorita – pro kaˇzdouhodnotu priority definov´anoˇcasov´ekvantum • sd´ılen´ıˇcasu (time-shared) – priorita 0 aˇz59 – promˇenn´advousloˇzkov´apriorita, pevn´auˇzivatelsk´aa promˇenn´asyst´emov´aˇc´ast– pokud proces hodnˇevyuˇz´ıv´a procesor, je mu sniˇzov´anapriorita (a zvˇetˇsov´anoˇcasov´e kvantum)

• syst´emov´atˇr´ıda je pouˇz´ıv´anapouze j´adrem,uˇzivatelsk´yproces bˇeˇz´ıc´ıv reˇzi- mu j´adrasi ponech´av´asvou pl´anovac´ıcharakteristiku. • procesy ve tˇr´ıdˇere´aln´ehoˇcasumaj´ınejvyˇsˇs´ıprioritu, proto mus´ıb´ytspr´avnˇe nakonfigurov´any, aby nezablokovaly zbytek syst´emu. • jestliˇzeje proces ve tˇr´ıdˇesd´ılen´ıˇcasuusp´ana ˇcek´ana nˇejakou ud´alost,je mu doˇcasnˇepˇriˇrazenasyst´emov´apriorita. Po probuzen´ıse takov´yproces dostane na procesor dˇr´ıve, neˇzostatn´ıprocesy, kter´enesp´ı. • pevn´aˇc´astpriority procesu ve tˇr´ıdˇesd´ılen´ıˇcasuse d´anastavit pomoc´ı int setpriority(int which, id t who, int prio ); nebo int nice(int incr ); Hodnota which ud´av´aco bude v argumentu who. Pokud je napˇr. which PRIO PGRP, bude v who ˇc´ısloskupiny proces˚u.Pozor na vol´an´ı nice kter´e vrac´ı novou hodnotu nice. Protoˇzeje -1 validn´ı hodnota, je potˇrebapˇred vol´an´ıvyˇcistit errno a pokud funkce vr´at´ı-1 tak ji zkontrolovat. • prioritn´ı tˇr´ıdu a hodnotu nice dan´ehoprocesu lze zobrazit pˇrep´ınaˇcem-l programu ps(1) nebo pomoc´ıspecifikace hodnot kter´ese maj´ıvypsat. • Pˇr´ıklad:hodnoty priority maj´ına r˚uzn´ych syst´emech r˚uzn´eˇsk´aly. Napˇr.na Mac OS X 10.9 m´aspuˇstˇen´yproces hodnotu priority 30, po zv´yˇsen´ıhodnoty nice (proces je ”hodnˇejˇs´ı”naostatn´ıprocesy a dobrovolnˇetedy sn´ıˇzilsvoji prioritu) se mu hodnota prorita sn´ıˇz´ına 21 coˇzna Mac OS X znamen´ai sn´ıˇzen´ıpriority:

126 $ sleep 200 & [1] 36877 $ ps -O pri,nice -p $! PID PRI NI TT STAT TIME COMMAND 36877 31 0 s003 S 0:00.00 sleep 200 $ renice 10 -p $! $ ps -O pri,nice -p $! PID PRI NI TT STAT TIME COMMAND 36877 21 10 s003 SN 0:00.00 sleep 200

Na Linuxu 3.10 to ale bude vypadat jinak - po zv´yˇsen´ıhodnoty nice se zv´yˇs´ıi hodnota priority, to ale v t´etoverzi znamen´a,ˇze proces bude bˇeˇzets prioritou niˇzˇs´ı.

Skupiny proces˚u,ˇr´ızen´ıtermin´al˚u

• kaˇzd´yproces patˇr´ıdo skupiny proces˚u,tzv. process group • kaˇzd´askupina m˚uˇzem´ıtvedouc´ıproces, tzv. group leader • kaˇzd´yproces m˚uˇzem´ıtˇr´ıd´ıc´ıtermin´al(je to obvykle login termin´al),tzv. controlling terminal • speci´aln´ısoubor /dev/tty je asociov´ans ˇr´ıd´ıc´ımtermin´alem kaˇzd´ehoprocesu • kaˇzd´ytermin´alje asociov´anse skupinou proces˚u,tato skupina se naz´yv´aˇr´ıd´ıc´ıskupina (controlling group) • kontrola job˚u(job control) je mechanizmus, jak pozastavovat a probouzet skupiny proces˚ua ˇr´ıditjejich pˇr´ıstupk termin´al˚um • session (relace) je kolekce skupin proces˚uvytvoˇren´apro ´uˇcely ˇr´ızen´ıjob˚u

• kdyˇzse uˇzivatel pˇrihl´as´ıdo syst´emu, je vytvoˇren´anov´arelace, kter´ase skl´ad´a z jedn´eskupiny proces˚u,ve kter´eje jeden proces – ten kter´yvykon´av´a uˇzivatel˚uvshell. Tento proces je z´aroveˇnvedouc´ı t´eto jedin´eskupiny pro- ces˚ua tak´eje vedouc´ırelace. V pˇr´ıpadˇe,ˇzejob control je povolen, kaˇzd´y pˇr´ıkaz nebo kolona pˇr´ıkaz˚uvytvoˇr´ınovou skupinu proces˚u,jeden z proces˚u v kaˇzd´eskupinˇese vˇzdystane vedouc´ımprocesem dan´eskupiny. Jedna ze skupin m˚uˇzebˇeˇzetna popˇred´ı,ostatn´ıbˇeˇz´ına pozad´ı.Sign´aly, kter´ejsou ge- nerovan´ez kl´avesnice (tj. stiskem kombinace kl´aves, nemysl´ıse t´ımspuˇstˇen´ı pˇr´ıkazu kill!), jsou zasl´any pouze skupinˇe,kter´abˇeˇz´ına popˇred´ı. • pokud job control nen´ızapnut, znamen´aspustˇen´ıpˇr´ıkazu na pozad´ıpouze to, ˇzeshell neˇcek´ana jeho ukonˇcen´ı.Existuje pouze jedna skupina proces˚u,

127 sign´alyz kl´avesnice se pos´ılaj´ıvˇsemproces˚umbeˇz´ıc´ımna popˇred´ıi na pozad´ı. Nelze pˇresouvat procesy z pozad´ına popˇred´ıa naopak. • kdyˇzproces, kter´ym´akontroln´ıtermin´al,otevˇresoubor /dev/tty, tak se aso- ciuje se sv´ymkontroln´ımtermin´alem.Tj. pokud dva r˚uzn´eprocesy z r˚uzn´ych relac´ıotevˇroutento soubor, pˇristupuj´ıoba k r˚uzn´ymtermin´al˚um. • v bashi se skupina proces˚u(job) pozastav´ıpomoc´ı Ctrl-Z, a rozbˇehnepˇres ,,fg %N” kde N je ˇc´ıslojobu podle v´ypisupˇr´ıkazu jobs. V´ıceinformac´ıviz sekce ,,JOB CONTROL” v manu´alov´estr´ancepro bash.

Identifikace procesu

pid t getpid(void); • vrac´ıproces ID volaj´ıc´ıho procesu.

pid t getpgrp(void); • vrac´ıID skupiny proces˚u,do kter´epatˇr´ıvolaj´ıc´ıproces.

pid t getppid(void); • vrac´ıproces ID rodiˇce.

pid t getsid(pid t pid ); • vrac´ıgroup ID vedouc´ıhoprocesu session (sezen´ı,termin´alov´e relace) pro proces pid (0 znamen´apro volaj´ıc´ıproces)

skupiny proces˚u umoˇzˇnuj´ıpos´ılatsign´alynajednou cel´eskupinˇe. session (relace, sezen´ı)je kolekce proces˚uvytvoˇren´apro ´uˇcelyˇr´ızen´ıprac´ı(job control). Procesy sezen´ısd´ılej´ıjeden ˇr´ıd´ıc´ıtermin´al. Session zahrnuje jednu nebo v´ıceskupin proces˚u.Max. jedna skupina v r´amcisezen´ıbˇeˇz´ına popˇred´ı (foreground process group) a m´apˇr´ıstupk ˇr´ıdic´ımu termin´alupro vstup i v´ystup,ostatn´ıbˇeˇz´ına pozad´ı(background process groups) a maj´ık ˇr´ıdic´ımu termin´alupˇr´ıstup volitelnˇejen pro v´ystupnebo v˚ubec (nepovolen´aoperace s termin´alempozastav´ıproces). rodiˇcovsk´yproces: Kaˇzd´yproces (kromˇe swapperu, pid == 0) m´arodiˇce,tj. proces, kter´yho stvoˇrilvol´an´ım fork. Jestliˇzerodiˇcskonˇc´ıdˇr´ıve neˇzd´ıtˇe, adoptivn´ımrodiˇcemse st´av´aproces init, kter´yse tak´epostar´ao uklizen´ı zombie po skonˇcen´ıprocesu. • Programatick´ezjiˇst’ov´an´ıinformac´ıo ostatn´ıch procesech lze pomoc´ınestan- dardn´ıch rozhran´ı(napˇr.knihovna libproc na Solarisu postaven´ana file- syst´emu procfs, kter´yje pˇripojen pod /proc).

128 • Pozor na to, ˇzezjiˇst’ovat ˇzerodiˇcskonˇcilpomoc´ıkontroly hodnoty vr´acen´ez getppid na hodnotu 1 (coˇzje bˇeˇznˇeproces init resp. jeho ekvivalent), nen´ı portabiln´ı. V r˚uzn´ych virtualizovan´ych prostˇred´ıch (PID namespaces v Linux, Zones v Solarisu) to nemus´ıplatit. Viz pˇr´ıklad session/getppid.c .

Nastaven´ıskupiny/sezen´ı

int setpgid(pid t pid, pid t pgid ); • nastav´ıprocess group ID procesu s pid na pgid.

pid t setsid(void); • vytvoˇr´ınovou session, volaj´ıc´ıproces se stane vedouc´ımsezen´ıi skupiny proces˚u.

• pro vol´an´ı setpgid plat´ı: 1. pid == pgid : proces s pid se stane vedouc´ımskupiny proces˚u 2. pid != pgid : proces s pid se stane ˇclenemskupiny proces˚u • Proces, kter´yjeˇstˇenen´ıvedouc´ımskupiny proces˚u,se m˚uˇzest´atvedouc´ım sezen´ıa z´aroveˇnskupiny proces˚uvol´an´ım setsid. Jestliˇzeproces uˇzje ve- douc´ımskupiny, setsid selˇze,pak je tˇrebaprov´est fork a setsid zavolat v synovsk´emprocesu. Takov´yproces nem´aˇr´ıdic´ıtermin´al,m˚uˇzeho z´ıskat otevˇren´ım termin´alu, kter´yjeˇstˇenen´ıˇr´ıdic´ım termin´alemsezen´ı, kdyˇzpˇri open neuvede pˇr´ıznak O NOCTTY, nebo jin´ymimplementaˇcnˇez´avisl´ymzp˚uso- bem.

129 Vytvoˇren´ıprocesu: fork()

getpid() == 1234 switch(pid = fork()) { case -1: /* Chyba */ case 0: /* D´ıtˇe */ default: /* Rodiˇc*/ }

d´ıtˇe(nov´yproces)rodiˇc(pokraˇcuje)

getpid()==1234, pid==2345 getpid()==2345, pid==0 switch(pid = fork()) { switch(pid = fork()) { case -1: /* Chyba */ case -1: /* Chyba */ case 0: /* D´ıtˇe */ case 0: /* D´ıtˇe */ default: /* Rodiˇc*/ default: /* Rodiˇc*/ } }

• d´ıtˇeje t´emˇeˇrpˇresnoukopi´ırodiˇce. Z´akladn´ıatributy, kter´ese liˇs´ı,jsou: – PID procesu a parent PID – pokud mˇelrodiˇcv´ıcevl´aken, m´asyn pouze to, kter´e fork zavolalo; o tom v´ıcena stranˇe 223, aˇzse dostaneme k vl´akn˚um.Tyto informace by kaˇzdop´adnˇemˇelyb´ytv manu´alov´estr´ance fork(2). – ´uˇctovac´ıˇcasyse nastav´ına 0 – nedˇed´ıse nastaven´ı alarm a z´amkysoubor˚u • co je d˚uleˇzit´eje, ˇzetabulky deskriptor˚ujsou stejn´ev obou procesech, ˇc´ımˇz v´ıceproces˚um˚uˇzesd´ıleta posunovat spoleˇcnoupozici v souboru, a tak´eˇze masky sign´al˚use nemˇen´ı,viz strana 158. • pro urychlen´ıa menˇs´ıspotˇrebupamˇetise adresov´yprostor nekop´ıruje,ale pouˇz´ıv´ase mechanizmus copy-on-write. • je logick´e,ˇzepˇri´uspˇeˇsn´emproveden´ıvol´an´ıotec dostane jako n´avratovou hodnotu vol´an´ı fork PID syna a syn ˇc´ıslo0; syn si totiˇzm˚uˇzevelmi jednodu- ˇsesv˚ujvlastn´ıPID zjistit vol´an´ım getpid. Otec ale neum´ıjednoduˇsezjistit PID syna, nav´ıcv situaci, pokud jiˇzdˇr´ıve vytvoˇrilsyny jin´e.

• pˇr´ıklad: fork/fork.c • zaj´ımavost´ım˚uˇzeb´ytvol´an´ı vfork, kter´ymse kdysi obch´azelprobl´em,kdy draze vytvoˇren´yproces byl okamˇzitˇepˇreps´ann´asledn´ymvol´an´ım exec. Tento probl´embyl d´avnovyˇreˇsenjiˇzzm´ınˇen´ympouˇzit´ım mechanizmu copy-on- write, ale pˇr´ıklad fork/vfork.c ukazuje, jak toto vol´an´ıfungovalo.

130 Spuˇstˇen´ıprogramu: exec extern char **environ; int execl(const char *path, const char *arg0, ... ); • spust´ıprogram definovan´ycelou cestou path, dalˇs´ıargumenty se pak pˇredaj´ıprogramu v parametrech argc a argv funkce main. Seznam argument˚uje ukonˇcenpomoc´ı (char *)0, tj. NULL. arg0 by mˇelobsahovat jm´enoprogramu (tj. ne celou cestu) • ´uspˇeˇsn´evol´an´ı execl se nikdy nevr´at´ı,protoˇzespuˇstˇen´y program zcela nahrad´ıdosavadn´ıadresov´yprostor procesu. • program dˇed´ıpromˇenn´eprostˇred´ı,tj. obsah environ. • handlery sign´al˚use nahrad´ıimplicitn´ıobsluhou • zavˇrouse deskriptory soubor˚u,kter´emaj´ınastaven´ypˇr´ıznak FD CLOEXEC (implicitnˇenen´ınastaven).

• o sign´alech v´ıcena stranˇe 147

• v path mus´ıb´ytcel´a(absolutn´ınebo relativn´ı)cesta ke spustiteln´emu sou- boru. Obsah promˇenn´eprostˇred´ı PATH se pouˇz´ıv´ajen pˇrivol´an´ıch execlp a execvp, kdyˇzargument path neobsahuje znak ’/’. • nˇekdyse pouˇz´ıv´a argv[0] r˚uzn´eod jm´ena spustiteln´ehosouboru. Napˇr. login vloˇz´ına zaˇc´atekjm´enaspouˇstˇen´ehoshellu znak ’-’. Shell podle toho pozn´a,ˇzem´afungovat jako login-shell, tj. napˇr´ıkladnaˇc´ıst /etc/profile. • exec nepˇred´akontrolu naˇcten´emu programu v pamˇetipˇr´ımo,ale pˇresdyna- mick´ylinker (t´eˇznaz´yvan´y loader), pot´eco ho (= toho loadera) namapuje do adresov´ehoprostoru procesu. Loader n´aslednˇenamapuje potˇrebn´edyna- mick´eobjekty a teprve pot´epˇred´akontrolu aplikaci. Viz tak´estrana 35. Pro jednoduch´eovˇeˇren´ıstaˇc´ıvytvoˇritprogram obsahuj´ıc´ıpouze tˇrebavol´an´ı open. Tento program pak spust’te pomoc´ı truss(1) takto: truss ./a.out. Uvid´ıte,kter´avol´an´ıse pouˇzij´ıjeˇstˇepˇredt´ım,neˇzse zavol´a open. • exec nezmˇen´ıhodnoty RUID a RGID. A pokud je to program s nastaven´ym SUID bitem, tak se EUID a uschovan´eUID nastav´ına UID majitele spusti- teln´ehosouboru. • dneˇsn´ıunixov´esyst´emy um´ıspouˇstˇeti skripty, kter´ezaˇc´ınaj´ıˇr´adkem #!/interpreter path /interpreter name [args]

131 Varianty sluˇzby exec

int execv(const char *path, char *const argv []); • obdoba execl(), ale argumenty jsou v poli argv, jehoˇz posledn´ıprvek je NULL. int execle(const char *path, const char *arg0, ... , char *const envp []); • obdoba execl(), ale m´ısto environ se pouˇzije envp. int execve(const char *path, char *const argv [], char *const envp []); • obdoba execv(), ale m´ısto environ se pouˇzije envp. int execlp(const char *file, const char *arg0, ...); int execvp(const char *file, char *const argv []); • obdoby execl() a execv(), ale pro hled´an´ıspustiteln´eho souboru se pouˇzijepromˇenn´a PATH.

• l = list (tj. line´arn´ıseznam argument˚u), v = vector (tj. pole ukazatel˚una ˇretˇezce), e = environment (tj. pˇred´avaj´ıse promˇenn´eprostˇred´ı), p = PATH.

• kromˇe execlp a execvp je nutn´ejm´enoprogramu vˇzdyzad´avat celou cestu. • vˇsechny varianty kromˇe execle a execve pˇred´avaj´ıspouˇstˇen´emu programu tak´esv´eaktu´aln´ıprostˇred´ı,tj. obsah pole environ. • z mnˇenezn´am´ych historick´ych d˚uvod˚uneexistuje vol´an´ıs p a e dohromady.

• pˇr´ıklad: exec/exec-date.c • n´asleduj´ıc´ıpouˇzit´ıvol´an´ı execl je ˇspatnˇe,protoˇzemu chyb´ıpovinn´ypara- metr pro argv[0]:

execl("/bin/ls", NULL);

Na nˇekter´ych syst´emech to m´azaj´ımav´yefekt. Jelikoˇzje NULL br´anjako oˇcek´avan´y argv[0], dalˇs´ıdata na z´asobn´ıkujsou akceptov´anajako ukaza- tele na ˇretˇezce,dokud se nenalezne dalˇs´ı NULL. V naˇsempˇr´ıpadˇetak pˇr´ıkaz ls zkouˇs´ızobrazit informace o souborech, jako jejichˇzjm´enajsou pouˇzity ˇretˇezcenastaven´ıpromˇenn´ych prostˇred´ız pole environ, o nichˇzjiˇzv´ıme,ˇze se vol´an´ım execl spouˇstˇen´emu programu pˇred´avaj´ı:

$ ./a.out : BLOCKSIZE=K: No such file or directory : FTP_PASSIVE_MODE=YES: No such file or directory

132 : HISTCONTROL=ignoredups: No such file or directory : HISTSIZE=10000: No such file or directory ......

Form´atspustiteln´ehosouboru

• Common Object File Format (COFF) – starˇs´ıSystem V • Extensible Linking Format (ELF) – nov´yv SVR4 • ˇcastose mluv´ıo a.out form´atu,protoˇzetak se jmenuje (pokud nen´ıpouˇzitpˇrep´ınaˇc -o) v´ystuplinkeru.

• Form´atELF: hlaviˇcka souboru tabulka programov´ych hlaviˇcek sekce 1 . . sekce N tabulka hlaviˇceksekc´ı

• Standard nestanovuje form´atspustiteln´ehosouboru. I kdyˇzvˇetˇsinaunixov´ych syst´em˚upˇreˇslana ELF, st´alese najdou mainstreamov´esyst´emy pouˇz´ıvaj´ıc´ı jin´eform´aty. Napˇr.Mac OS X (coˇzje certifikovan´yUNIX) pouˇz´ıv´atzv. Mach- O form´at.Stejnˇejako ELF je strukturovan´y,odliˇsujese napˇr.v tom, ˇzeza hlaviˇckou n´asleduj´ıtzv. load commands, kter´ese odkazuj´ına sekce v dalˇs´ı ˇc´asti.Za nimi n´asleduj´ısamotn´esegmenty, kter´ese skl´adaj´ıze sekc´ı.Kaˇzd´y segment je ´usekvirtu´aln´ıpamˇeti,kterou dynamick´ylinker mapuje do adre- sov´ehoprostoru procesu. Kaˇzd´asekce obsahuje k´odnebo data dan´ehotypu. • Hlaviˇcka souboru (ELF header) obsahuje z´akladn´ıinformace o souboru. • Na Solarisu je k dispozici program elfdump umoˇzˇnuj´ıc´ızobrazen´ıprakticky vˇsech sekc´ıv ELF souboru a jejich obsahu v lidsky ˇciteln´eformˇe.V Linuxu lze pouˇz´ıtprogram readelf, jeho funkcionalita je ovˇsemproti elfdump omezena. • Tabulka programov´ych hlaviˇcek(program header table) je pˇr´ıtomnapouze u soubor˚uobsahuj´ıc´ıch spustiteln´eprogramy, zobraz´ıse pomoc´ı“elfdump -p”. Obsahuje informaci o rozvrˇzen´ıvirtu´aln´ıpamˇetiprocesu. • Sekce obsahuj´ıinstrukce, data, tabulku symbol˚u,relokaˇcn´ıdata, apod. • Tabulka hlaviˇcek sekc´ı(section header table) obsahuje sluˇzebn´ıinformace pro linker, “elfdump -c”.

133 • Nen´ıto tak d´avnoco nˇekter´eunixov´esyst´emy pˇreˇslyna ELF. Napˇr.OpenBSD pˇreˇsloz a.out form´atu(coˇzje dalˇs´ıform´atspustiteln´ych soubor˚u,viz a.out(5) man page na OpenBSD) na ELF ve verzi 3.4 v roce 2003. Proti ELFu je a.out mnohem jednoduˇsˇs´ıa m´enˇeobecn´y,hod´ıse tedy dobˇrena zkoum´an´ıfunda- ment´aln´ıch princip˚uzav´adˇen´ı spustiteln´ych soubor˚udo pamˇeti. Z´akladem hlaviˇcka (obsahuj´ıc´ınapˇr.informace o tom zda spustiteln´ysoubor vyˇzaduje sluˇzby run time linkeru nebo zda obsahuje Position Independent Code) a pak dalˇs´ıch nepovinn´ych 6 sekc´ı(text, data, relokace v textov´emsegmentu, relo- kace v datov´emsegmentu, tabulka symbol˚u,tabulka string˚ukoresponduj´ıc´ıch s jednotliv´ymisymboly). • Dnes je naprosto bˇeˇzn´eˇzevirtu´aln´ı adresy spustiteln´ehosouboru, nama- povan´ych knihoven, z´asobn´ıku a heapu jsou n´ahodn´e,mˇen´ıse pˇrikaˇzd´em spuˇstˇen´ıprocesu. Tato technika (Adress Space Layout Randomization) slouˇz´ı k znesnadnˇen´ı´utok˚u,kter´epotˇrebuj´ızn´atnapˇr.adresy symbol˚uv knihovnˇe libc nebo z´asobn´ıku.Poprv´es touto ideou pˇriˇselLinux, OpenBSD byl prvn´ı syst´emkter´yji zaˇcalpouˇz´ıvat pro vˇsechny programy implicitnˇe.R˚uzn´esys- t´emy aplikuj´ıtuto techniku s r˚uzn´ymiparametry a na r˚uzn´eˇc´astiprogramu. Obecnˇejivzato lze vn´aˇsetn´ahodnost do dalˇs´ıch ˇc´ast´ısyst´emu (napˇr.ID pro- ces˚u,inici´aln´ısekvenˇcn´ıˇc´ıslapro TCP apod.).

Ukonˇcen´ıprocesu

void exit(int status ); • ukonˇc´ıproces s n´avratov´ymk´odem status. • nikdy se nevr´at´ına instrukci n´asleduj´ıc´ıza vol´an´ım. pid t wait(int *stat loc ); • poˇck´a,aˇzskonˇc´ınˇekter´ysynovsk´yproces, vr´at´ıjeho PID a do stat_loc uloˇz´ın´avratov´yk´od,kter´ylze d´aletestovat: – WIFEXITED(stat val) . . . proces volal exit() – WEXITSTATUS(stat val) . . . argument exit() – WIFSIGNALED(stat val) . . . proces dostal sign´al – WTERMSIG(stat val) . . . ˇc´ıslosign´alu – WIFSTOPPED(stat val) . . . proces pozastaven – WSTOPSIG(stat val) . . . ˇc´ıslosign´alu pid t waitpid(pid t pid, int *stat loc, int opts ); • ˇcek´an´ına jeden proces.

• status loc roven NULL znaˇc´ıignoraci statusu • funkce exit funguje jako exit s t´ım,ˇzese neprov´ad´ıflush stdio stream˚ua nevolaj´ıse funkce nastaven´epomoc´ı atexit

134 • ve standardu je jeˇstˇe WIFCONTINUED(stat val), coˇzznaˇc´ıopˇetn´erozbˇehnut´ı procesu po jeho pˇredchoz´ımzastaven´ı,je to ale souˇc´astjist´ehorozˇs´ıˇren´ı,kter´e nemus´ıvˇsechny syst´emy podporovat.

• pozn´amka – pozastavit proces lze pomoc´ı,,kill -STOP ”, rozbˇehnout pak pˇres,,kill -CONT ”. • opts ve waitpid jsou OR-kombinace n´asleduj´ıch pˇr´ıznak˚u: – WNOHANG . . . neˇcek´a,pokud nen´ıstatus okamˇzitˇek dispozici – WUNTRACED . . . vr´at´ı status i zastaven´ych proces˚u, kter´ejeˇstˇenebyly testov´any po jejich zastaven´ı. WSTOPPED m˚uˇzena nˇekter´ych syst´emech b´ytsynonymem pro WUNTRACED, nen´ıale souˇc´ast´ınormy. – WCONTINUED . . . vr´at´ıstatus i tˇech proces˚u,kter´ejeˇstˇenebyly testov´any od pokraˇcov´an´ıprocesu po zastaven´ı.Bez tohoto pˇr´ıznakunejsou takov´e procesy reportov´any. Souˇc´ast´ıstejn´ehorozˇs´ıˇren´ıjako WIFCONTINUED. – pro WUNTRACED a WCONTINUED plat´ı,ˇzev pˇrenositeln´ych aplikac´ıch byste tyto pˇr´ıznakymˇelipouˇz´ıvat jen kdyˇzje v definov´anomakro POSIX JOB CONTROL. • pid ve waitpid:

– == -1 . . . libovoln´ed´ıtˇe – > 0 . . . jedno d´ıtˇe – == 0 . . . d´ıtˇeve stejn´eskupinˇeproces˚ujako volaj´ıc´ıproces – < -1 . . . d´ıtˇeve skupinˇe abs(pid)

• rodiˇcby mˇelvˇzdyna sv´edˇetizavolat wait nebo waitpid, protoˇzejinak se v syst´emu hromad´ı zombie (ukonˇcen´eprocesy, kter´epouze ˇcekaj´ı,aˇzsi rodiˇcpˇreˇctejejich n´avratovou hodnotu). Hromadˇen´ıtˇechto zombie proces˚uv tabulce proces˚ukernelu m˚uˇzeskonˇcitvyˇcerp´an´ımveˇsker´evoln´epamˇeti,takˇze pozor na to. Pokud takov´yrodiˇcs´amskonˇc´ı, vˇsechny jeho syny adoptuje process init, kter´yse tak postar´ai o vˇsechny zombie procesy.

• pˇr´ıklad: wait/wait.c

135 Pˇr´ıklad:spuˇstˇen´ıprogramu a ˇcek´an´ı

int status; pid = fork()

d´ıtˇerodiˇc

if(pid > 0) else execl("/bin/ls", "ls", "/", NULL);

/bin/ls int main(int argc, char *argv[]) { ... exit(result); wait(&status); }

• toto je klasick´yzp˚usobjak spustit nˇejak´yprogram a po jeho skonˇcen´ıpo- kraˇcovat. Rodiˇcnemus´ıjen ˇcekat na ukonˇcen´ıpotomka, ale m˚uˇzevykon´avat d´alsv˚ujk´od. • pozor na to, ˇzeaˇckoli to na obr´azkutak vypad´a,n´avratov´ahodnota je pouze souˇc´asttoho, co dostanete z vol´an´ı wait. Na jej´ız´ısk´an´ıje potˇrebapouˇz´ıt makra z pˇredchoz´ıhoslajdu.

136 Roura: pipe()

int pipe(int fildes [2]); • vytvoˇr´ırouru a dva deskriptory – fildes[0] . . . ˇcten´ız roury – fildes[1] . . . z´apisdo roury • roura zajiˇst’uje synchronizaci ˇcten´ıa z´apisu: – zapisuj´ıc´ıproces se zablokuje, kdyˇzje roura pln´a, – ˇctouc´ıproces se zablokuje, kdyˇzje roura pr´azdn´a. • ˇctouc´ıproces pˇreˇctekonec souboru (tj. read() vr´at´ı 0), pokud jsou uzavˇreny vˇsechny kopie fildes[1]. • pojmenovan´aroura (vytvoˇren´avol´an´ım mkfifo()) funguje stejnˇe,ale m´apˇridˇelen´ejm´enov syst´emu soubor˚ua mohou ji tedy pouˇz´ıvat libovoln´eprocesy.

• nepojmenovanou rouru vytv´aˇr´ıjeden proces a m˚uˇzeji pˇredatpouze sv´ym potomk˚um(pomoc´ı deskriptor˚uzdˇedˇen´ych pˇri fork). Toto omezen´ı se d´a obej´ıtpomoc´ıpˇred´an´ıotevˇren´ehodeskriptoru pˇresunix-domain socket.

• jestliˇzefunkce write zap´ıˇsedo roury nejv´yˇse PIPE BUF (syst´emov´akonstanta) bajt˚u,je zaruˇceno,ˇzez´apisbude atomick´y,tj. tato data nebudou proloˇzena daty zapisovan´ymisouˇcasnˇejin´ymiprocesy.

• v normˇeSUSv3 nen´ıspecifikov´ano,zda fildes[0] je tak´eotevˇren´ypro z´apis a zda fildes[1] je t´eˇzotevˇren´ypro ˇcten´ı.Pozor na to, ˇzenapˇr´ıkladFreeBSD a Solaris maj´ıroury obousmˇern´e,ale Linux (kdyˇzjsem se naposledy d´ıval) ne. Je proto velmi vhodn´epoˇc´ıtatpouze s jednosmˇern´ymirourami.

• d˚uleˇzit´e: pro ˇcten´ı/z´apisz/do roury plat´ıstejn´epodm´ınky jako pro pojme- novanou rouru, jak jsou uvedeny na stranˇe 98. To tak´eznamen´a,ˇzejedin´y zp˚usob,jak ˇcten´aˇrovi roury “poslat” end-of-file je, ˇzevˇsichni zapisovatel´e mus´ızavˇr´ıtpˇr´ısluˇsn´ydeskriptor pro z´apis,pˇr´ıpadnˇevˇsechny takov´edeskrip- tory, maj´ı-lijich v´ıce.

• pˇr´ıklady: pipe/broken-pipe.c , pipe/main.c

137 Pˇr´ıklad:roura mezi dvˇemaprocesy

shell: ls / | more int pd[2]; pipe(pd); switch(fork()) {

konzument (rodiˇc)producent (d´ıtˇe) case 0: default: close(1); close(0); dup(pd[1]); dup(pd[0]); close(pd[0]); close(pd[0]); close(pd[1]); close(pd[1]); execl("/bin/ls", "ls", execl("/bin/more", "/", NULL); "more", NULL); pd[1] pd[0] /bin/ls /bin/more

• zavˇren´ız´apisov´ehodeskriptoru pd[1] (ozn. .) v procesu konzumenta je nutn´e, protoˇzejinak se na rouˇrenikdy nedetekuje konec souboru. • ˇctec´ıdeskriptor v procesu producenta pd[0] je tak´evhodn´ezav´ırat(ozn. .), protoˇzekdyˇzkonzument pˇredˇcasnˇeskonˇc´ı,dostane producent sign´al SIGPIPE. Kbyby deskriptor v producentovi nebyl zavˇren,producent se nedozv´ı,ˇzekon- zument skonˇcil,a po naplnˇen´ıbufferu roury v j´adruse zablokuje. • pokud nem´amejistotu, ˇzepˇredvol´an´ım pipe byl otevˇrendeskriptor 0, mus´ıme v producentovi pouˇz´ıt dup2(pd[1], 1), protoˇze dup(pd[1]) by mohl vr´atit deskriptor 0 m´ısto poˇzadovan´eho 1. Tak´eje tˇrebatestovat, zda nenastala situace pd[1] == 1, abychom si nechtˇenˇenezavˇrelirouru. Podobnˇeje tˇreba otestovat pd[0] == 0 v konzumentovi. • je lepˇs´ıvytv´aˇret rouru od syna k otci, protoˇzetypicky nejdˇr´ıvskonˇc´ıproces zapisuj´ıc´ıdo roury, ˇctouc´ıproces pˇreˇctezbyl´adata, zpracuje je, nˇecovyp´ıˇse a teprve pak skonˇc´ı. D˚uvodem je to, ˇzeshell, kter´ypˇr´ısluˇsnoukolonu pˇr´ıkaz˚uspouˇst´ı,ˇcek´ana ukonˇcen´ıotce a o jeho syny se nezaj´ım´a.Kdyby tedy smˇeˇrovala roura od otce k synovi, otec jako producent dat skonˇc´ı,shell vyp´ıˇseprompt, ale pak jeˇstˇesyn, kter´ypln´ıfunkci konzumenta, m˚uˇzevypsat nˇejak´yv´ystup.Moˇzn´ym ˇreˇsen´ımje ˇcek´an´ıotce na skonˇcen´ısyna, jenˇzeto se ned´azajistit, pokud otec provede exec. • p˚uvodn´ı Bourne shell stav´ı rouru tak, ˇzeposledn´ı proces v rouˇrevytvoˇr´ı pˇredposledn´ıjako sv´ehosyna, ten vytvoˇr´ıpˇredchoz´ıproces a tak se postupuje aˇzk zaˇc´atkuroury.

138 • v shellu bash jsou vˇsechny procesy v rouˇrepˇr´ımopotomky shellu (shell vol´a fork tolikr´at,jak dlouh´aje roura). Shell pˇredvyps´an´ımpromptu ˇcek´a,aˇz vˇsechny procesy roury skonˇc´ı.

Sd´ılen´apamˇet’ – ´uvod • pajpy a soubory jako metody meziprocesov´ekomunikace vyˇzaduj´ısyst´emov´avol´an´ı • v´yhoda: procesy nemohou poˇskodit adresov´yprostor jin´eho procesu • nev´yhoda: velk´areˇziepro syst´emov´avol´an´ı,typicky read, write • sd´ılen´apamˇet’ je namapov´an´ıˇc´astipamˇetido adresov´eho prostoru v´ıceproces˚u • odstranˇen´ınev´yhody, ztr´atadosavadn´ıv´yhody • synchronizace pˇr´ıstupu do sd´ılen´epamˇeti – System V semafory – POSIX semafory bez nutnosti syst´emov´ehovol´an´ıv bˇeˇzn´em pˇr´ıpadˇe

• mapov´an´ısoubor˚udo pamˇetije jednou z implementac´ısd´ılen´epamˇeti.Pro popis ´usekusd´ılen´epamˇetipouˇz´ıv´asoubor. • takto implementovan´asd´ılen´apamˇet’ je tedy pravidelnˇezapisov´anana disk • pro sd´ılen´ıbez reˇziez´apisuzmˇenˇen´ych dat na disk je moˇzn´epouˇz´ıt memory based filesyst´em,napˇr´ıklad tmpfs (Solaris, NetBSD – zde byl tmpfs naps´an v roce 2005 jako souˇc´ast Summer of Code sponzorovan´ehofirmou Google, FreeBSD m´apodobnou vlastnost pod n´azvem memory disk). Jako tzv. bac- king store pro pamˇet’ov´estr´ankypatˇr´ıc´ıtˇemto filesyst´em˚umje obecnˇemoˇzn´e pouˇz´ıtswap oblast na disku.

• pro synchronizaci pˇr´ıstupudo sd´ılen´epamˇetise vˇetˇsinoupouˇz´ıvaj´ısemafory.

139 Mapov´an´ısoubor˚udo pamˇeti(1)

void *mmap(void *addr, size t len, int prot, int flags, int fildes, off t off ); • do pamˇet’ov´ehoprostoru procesu od adresy addr (0 . . . adresu pˇridˇel´ıj´adro)namapuje ´usekd´elky len zaˇc´ınaj´ıc´ına pozici off souboru reprezentovan´ehodeskriptorem fildes. • vrac´ıadresu namapovan´eho´usekunebo MAP FAILED. • v prot je OR-kombinace PROT READ (lze ˇc´ıst), PROT WRITE (lze zapisovat), PROT EXEC (lze spouˇstˇet),nebo PROT NONE (nelze k dat˚umpˇristupovat). • ve flags je OR-kombinace MAP PRIVATE (zmˇeny jsou priv´atn´ı pro proces, neukl´adaj´ıse do souboru), MAP SHARED (zmˇeny se ukl´adaj´ıdo souboru), MAP FIXED (j´adronezmˇen´ıaddr).

• Pˇr´ıklady: mmap/reverse.c , mmap/map-nocore.c

• v pˇr´ıznac´ıch mus´ıb´ytpˇr´ıtomen pr´avˇejeden z MAP PRIVATE a MAP SHARED • mapov´an´ısoubor˚udo pamˇetije alternativou ke zpracov´an´ısoubor˚upomoc´ı read, write, lseek. Po namapov´an´ılze se souborem pracovat jako s datovou strukturou v pamˇeti.Soubor se nekop´ırujecel´ydo pamˇeti,alokuj´ıse pouze str´ankyna kter´ese pˇristupuje.Pokud je potˇrebastr´ankuuvolnit, obsah se ukl´ad´azpˇetdo souboru (kdyˇzje pouˇzit MAP SHARED – tento zp˚usobnama- pov´an´ıje tedy ekvivalentn´ıtomu, kdy program zap´ıˇsedo stejn´ehosouboru pomoc´ı write(2)) nebo do swapu – pouˇz´ıv´ase mechanizmus copy-on-write (pˇri MAP PRIVATE). • pro namapov´an´ısouboru do pamˇetitedy potˇrebujisoubor nejdˇr´ıve otevˇr´ıt pomoc´ı open. M´odv prot nem˚uˇzeb´yt“vyˇsˇs´ı”neˇzbylo specifikov´anov m´odu pro open. Pouˇzit´ı MAP FIXED se nedoporuˇcuje, protoˇzeto m˚uˇzeb´ytprobl´em pro pˇrenositelnostk´odu. • varov´an´ı: toto se t´yk´apouze MAP SHARED – pokud je soubor jin´ymprocesem zkr´acentak, ˇzezkr´acen´ıse t´yk´ai pr´avˇenamapovan´eˇc´asti,pˇripˇr´ıstupu do takov´epamˇetije procesu zasl´ansign´al SIGBUS resp. SIGSEGV. Reˇsen´ımˇ je pouˇz´ıtmandatory locking, to ale nen´ıvˇsude implementov´ano.V pˇr´ıpadˇe,ˇze je namapovan´apamˇet’ pouˇzitajako parametr vol´an´ı write, sign´alse nepoˇsle, protoˇze write vr´at´ı-1 a errno je nastaveno na EFAULT. • pˇripouˇzit´ı MAP PRIVATE vid´ımna Solarisu vˇsechny zmˇeny proveden´ejin´ymi procesy, kter´enamapovaly sd´ılenˇe,aˇzdo t´edoby, kdy do str´ankyzap´ıˇsu

140 – v tom okamˇziku se vytvoˇr´ı kopie str´ankya dalˇs´ı takov´ezmˇeny jiˇzne- vid´ım.Na FreeBSD tyto zmˇeny nevid´ımani pˇredz´apisem.Viz specifikace: ,,It is unspecified whether modifications to the underlying object done after the MAP PRIVATE mapping is established are visible through the MAP PRIVATE mapping.” • hodnota off+len m˚uˇzepˇrekraˇcovat aktu´aln´ıvelikost souboru, za konec sou- boru ale nelze zapisovat a soubor tak prodlouˇzit- proces by obdrˇzelsign´al SIGBUS resp. SIGSEGV, viz pˇr´ıklad mmap/lseek.c . Sign´aldostanu stejnˇe tak v situaci, kdy do read-only namapovan´ehosegmentu zkus´ımzapsat (je to logick´e,pˇriˇrazen´ınem´an´avratovou hodnotu kterou byste mohli otestovat). • mapuje se vˇzdypo cel´ych str´ank´ach, hodnoty off (a pˇri MAP FIXED i addr) mus´ıb´ytspr´avnˇezarovnan´e.Posledn´ıstr´anka je za koncem souboru doplnˇena nulami a tento ´usekse nikdy nepˇrepisujedo souboru. • Anonymn´ımapov´an´ılze sd´ıletmezi r˚uzn´ymiprocesy pouze pomoc´ı fork(). Jedinou alternativou je pamˇet’ sd´ılen´apomoc´ısyst´emov´ehovol´an´ı shmat. • pˇr´ıstupdo namapovan´eho´useku,ale za posledn´ıexistuj´ıc´ıstr´ankunamapo- van´ehoobjektu, zp˚usob´ısign´al SIGBUS resp. SIGSEGV. Neplat´ıto vˇsude´uplnˇe pˇresnˇe,viz pˇr´ıklad mmap/sigbus.c .

• Pˇripouˇzit´ı MAP FIXED namapov´an´ısouboru nahrad´ıpˇr´ıpadn´epˇredchoz´ıma- pov´an´ıstr´anekv rozsahu. addr aˇz addr+len-1, viz pˇr´ıklad mmap/override.c .

• existuj´ıc´ırozˇs´ıˇren´ıpro flagy (nejsou souˇc´ast´ıSUSv3):

– pˇr´ıznak MAP ANON ve FreeBSD a Solarisu – vytvoˇren´ıanonymn´ıhoseg- mentu bez vazby na soubor, deskriptor mus´ıb´yt -1. Mapuje se tak ano- nymn´ıobjekt, kter´yjak v´ımem´am´ıstofyzick´ehouloˇzen´ına swapu (tedy nen´ı trval´e).Linux m´apodobnou funkcionalitu pˇres MAP ANONYMOUS. Tento pˇr´ıznak pouˇz´ıvaj´ı pamˇet’ov´ealok´atory, kter´epracuj´ı s vol´an´ım mmap, viz tak´estrana 118. – v IRIXu lze pomoc´ı MAP AUTOGROW automaticky zvˇetˇsitnamapovan´yob- jekt pˇripˇr´ıstupu za jeho st´avaj´ıc´ıkonec.

• bˇeˇzn´ympˇr´ıkazem, kter´ypouˇz´ıv´amapov´an´ısoubor˚udo pamˇeti,je cat(1). C´ıstzˇ takov´epamˇetije prostˇerychlejˇs´ıneˇzopakovanˇevolat read, kde je nutn´ese pro kaˇzd´etakov´evol´an´ıpˇrepnoutz uˇzivatelsk´ehoreˇzimu do reˇzimu j´adraa zpˇet.

141 Mapov´an´ısoubor˚udo pamˇeti(2)

int msync(void *addr, size t len, int flags ); • zap´ıˇsezmˇenˇen´estr´ankyv ´usekulen bajt˚uod adresy addr do souboru. Hodnota flags je OR-kombinace – MS ASYNC . . . asynchronn´ız´apis – MS SYNC . . . synchronn´ız´apis – MS INVALIDATE . . . zruˇsitnamapovan´adata, kter´ase liˇs´ıod obsahu souboru int munmap(void *addr, size t len ); • zap´ıˇsezmˇeny, zruˇs´ımapov´an´ıv d´elce len od adresy addr. int mprotect(void *addr, size t len, int prot ); • zmˇen´ıpˇr´ıstupov´apr´ava k namapovan´emu ´useku souboru. Hodnoty prot jsou stejn´ejako u mmap().

• uloˇzen´ızmˇendo souboru na disk je zaruˇcen´eaˇzpo proveden´ı msync nebo munmap, ale ostatn´ıprocesy, kter´emaj´ısoubor namapov´an,vid´ızmˇeny hned. • mapov´an´ıpamˇetia nastavov´an´ıpˇr´ıstupov´ych pr´avpouˇz´ıv´anapˇr.knihovna Electric Fence, kter´aslouˇz´ıpro ladˇen´ıchyb pˇripr´aci s dynamickou pamˇet´ı.

142 Pˇr´ıklad:mapov´an´ısoubor˚udo pamˇeti

int main(int argc, char *argv[]) { int fd, fsz; char *addr, *p1, *p2, c;

fd = open(argv[1], O RDWR); fsz = lseek(fd, 0, SEEK END); p1 = addr = mmap(0, fsz, PROT READ|PROT WRITE, MAP SHARED, fd, 0); p2 = p1 + fsz - 1; while(p1

• Tento program otoˇc´ıpoˇrad´ıznak˚uv souboru (zap´ıˇsesoubor od konce k za- ˇc´atku). • Jedna z hlavn´ıch v´yhod sd´ılen´ych segment˚uje moˇznostpracovat s daty v souboru pomoc´ı pointerov´earitmetiky. Obecnˇeje ale nutn´ed´atpozor na zarovn´an´ıpˇridereferenc´ıch; napˇr.na SPARCu dojde pˇritakov´em pˇr´ıstupu sign´al SIGBUS, viz pˇr´ıklad mmap/aligned.c .

143 Dynamick´ypˇr´ıstupke knihovn´am

void *dlopen(const char *file, int mode ); • zpˇr´ıstupn´ıknihovnu v souboru file, vr´at´ı handle nebo NULL. • v mode je OR-kombinace RTLD NOW (okamˇzit´erelokace), RTLD LAZY (odloˇzen´erelokace), RTLD GLOBAL (symboly budou glob´alnˇedostupn´e), RTLD LOCAL (nebudou glob´alnˇedostupn´e). void *dlsym(void *handle, const char *name ); • vr´at´ıadresu symbolu zadan´ehojm´enaz knihovny. int dlclose(void *handle ); • ukonˇc´ıpˇr´ıstupke knihovnˇe. char *dlerror(void); • vr´at´ıtextov´ypopis chyby pˇripr´acis knihovnami.

• pomoc´ıtˇechto funkc´ılze implementovat dynamicky nahr´avan´eplug-in mo- duly naˇc´ıtan´eaplikac´ıpodle potˇreby (napˇr.podle obsahu jej´ıhokonfiguraˇc- n´ıhosouboru). • dynamick´ymnaˇc´ıt´an´ımknihoven se tak´ed´avyˇreˇsitsituace, kdy potˇrebujeme vyuˇz´ıt nˇekolik knihoven, kter´edefinuj´ı symbol se stejn´ymjm´enem. Jedna knihovna se pˇr´ımopˇrilinkuje k programu, k ostatn´ımse pˇristupujepomoc´ı dlopen. • soubor mus´ı b´ytve spr´avn´emform´atu(sd´ılen´aknihovna .so ve form´atu ELF resp. form´atupodporovan´emna dan´emsyst´emu), napˇr´ıkladu gcc to znamen´apouˇz´ıtpˇrep´ınaˇc -shared, u cc na Solarisu (Sun Studio Compiler) je to pˇrep´ınaˇc -G. Na OS X (s form´atem Mach-O) je to -dynamiclib, knihovny maj´ıpˇr´ıponu .dynlib. • pokud cesta obsahuje znak /, bere se podle tvaru jako glob´aln´ınebo relativn´ı. Pokud lom´ıtko neobsahuje, pouˇzijese pro hledan´ıobjektu defaultn´ınastaven´ı dynamick´eholinkeru, typicky /lib a /usr/lib, kter´ese d´arozˇs´ıˇr´ıtpomoc´ı promˇenn´e LD LIBRARY PATH. Na jej´ıpouˇzit´ıovˇsempozor, viz pozn´amkyna stranˇe 37. • konstanty pro parametr mode funkce dlopen:

– RTLD NOW – vˇsechny relokace (vyˇreˇsen´ıvˇsech odkaz˚u)pro symboly na- lezen´ev pˇripojovan´emobjektu jsou provedeny okamˇzitˇepo nataˇzen´ı knihovny, aplikace m´ajistotu, ˇzejsou vˇsechny symboly pˇr´ıstupn´e

144 – RTLD LAZY – relokace mohou b´ytodloˇzeny aˇzdo chv´ıle pouˇzit´ı sym- bolu. Co to v praxi znamen´a?Pokud otevˇreteobjekt, kter´yz´avis´ına dalˇs´ıch objektech, dynamick´ylinker tyto ostatn´ı z´avisl´eobjekty ma- puje do pamˇeti,aˇzkdyˇzjsou opravdu potˇreba.M˚uˇzese tak st´at,ˇze z´avislostineexistuj´ı, ale vol´an´ı dlopen stejnˇeuspˇeje.U RTLD NOW se z´avisl´e objekty mapuj´ı do pamˇeti hned, a teprve pak dlopen vr´at´ı pˇr´ısluˇsn´yhandle. Na Solarisu m˚uˇzetedefaultn´ıchov´an´ıpro dynamick´y linker vynutit promˇenn´ymiprostˇred´ı LD BIND NOW a LD BIND LAZY. Pˇri konfliktu nastaven´ım´avˇzdypˇrednostnastaven´ı NOW, at’ jiˇzje glob´aln´ı nebo jen v m´oduvol´an´ı dlopen pˇrimapov´an´ıjednoho konkr´etn´ıhoob- jektu. Pˇrispouˇstˇen´ıaplikace jsou vˇsechny z´avisl´eobjekty defaultnˇema- povan´ehned, ale je moˇzn´ejednotliv´eknihovny linkovat pro ,,lazy bin- ding” pomoc´ı -z lazyload, viz manu´alov´estr´ankypro ld a ld.so.1. Pˇr´ıklad: dyn-lib/ld-lazy.c . – RTLD GLOBAL . . . symboly z knihovny mohou b´ytpouˇzity pˇrizpracov´an´ı relokac´ı v ostatn´ıch knihovn´ach a jsou dostupn´epomoc´ı dlopen(0, RTLD GLOBAL). Toto je defaultn´ınastaven´ıpro objekty mapovan´epˇri spuˇstˇen´ıprogramu. Pro dlopen je defaultn´ınastaven´ı RTLD LOCAL. To znamen´a,ˇzeje moˇzn´enamapovat stejnou knihovnu nˇekolikr´ata sym- boly se nebudou vz´ajemnˇepˇrekr´yvat. Pozor ale na to, kdyˇztakov´e knihovny budou pouˇz´ıvat symboly jin´ehoglob´aln´ıobjektu - napˇr. errno z libc.so. Takov´ysymbol je d´alespoleˇcn´ypro vˇsechny namapovan´eob- jekty, vˇcetnˇetˇech mapovan´ych pomoc´ı RTLD LOCAL. • speci´aln´ıhandle RTLD NEXT hled´asymbol pouze v knihovn´ach nahran´ych po knihovnˇe,ve kter´eje vol´an´ı dlsym. Hod´ı se pro pˇredefinov´an´ı existuj´ıc´ıch funkc´ı,pokud v redefinovan´efunkci potˇrebujeme volat p˚uvodn´ı.Knihovna s novou funkc´ıse nahr´av´ajako prvn´ı(napˇr.pomoc´ıpromˇenn´e LD PRELOAD), adresu p˚uvodn´ıfunkce z´ısk´avol´an´ım dlsym(RTLD NEXT, fn name ). Pˇr´ıklad: dyn-lib/rtld next.c .

• vˇsechny tyto funkce jsou souˇc´ast´ıdynamick´eholinkeru, kter´ym´akaˇzd´ady- namicky slinkovan´aaplikace namapovan´yve sv´emadresov´emprostoru. Viz tak´estrany 35a 131.

145 Pˇr´ıklad:zpˇr´ıstupnˇen´ıknihovny

char *err; void *handle; double y, x = 1.3; double (*fun)(double); char *libname = "libm.so", *fn name = "sin";

if ((handle = dlopen(libname, RTLD NOW)) == NULL) { fprintf(stderr, "%s\n", dlerror()); exit(1); } fun = dlsym(handle, fn name); if ((err = dlerror()) != NULL) fprintf(stderr, "%s\n", err); exit(1); y = fun(x); dlclose(handle);

• zde se vol´afunkce sin z knihovny matematick´ych funkc´ı libm.so. • funkce dlsym vr´at´ıadresu symbolu dan´ehojm´ena,ale vˇzdyjako ukazatel na void, neprob´ıh´aˇz´adn´atypov´akontrola ani nen´ık dispozici ˇz´adn´ainformace o typu symbolu. Ten, kdo tuto adresu pouˇz´ıv´a,mus´ı zajistit jej´ı spr´avn´e pˇretypov´an´ı.

• pˇripouˇzit´ıknihoven v C++ je tˇrebasi uvˇedomit,ˇzeC++ pouˇz´ıv´a name mangling, tj. do jm´enafunkce (metody) je zak´odov´anopˇr´ıpadn´ejm´enotˇr´ıdy nebo namespace a typy parametr˚u.

• pˇr´ıklad: dyn-lib/dlopen.c

146 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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

Sign´aly

• informuj´ıproces o v´yskytuurˇcit´eud´alosti • na uˇzivatelsk´e´urovni zpˇr´ıstupˇnuj´ımechanizmy pˇreruˇsen´ı • kategorie sign´al˚u: – chybov´eud´alosti generovan´ebˇeˇz´ıc´ımprocesem, napˇr. pokus o pˇr´ıstupmimo pˇridˇelenouoblast pamˇeti(SIGSEGV) – asynchronn´ıud´alosti vznikaj´ıc´ımimo proces, napˇr.sign´al od jin´ehoprocesu, vyprˇsen´ınastaven´ehoˇcasu (SIGALRM), odpojen´ıtermin´alu(SIGHUP), stisk Ctrl-C (SIGINT) • nejjednoduˇsˇs´ımechanizmus pro komunikaci mezi procesy – nesou pouze informaci o tom, ˇzenastala nˇejak´aud´alost. • vˇetˇsinouse zpracov´avaj´ıasynchronnˇe– pˇr´ıchod sign´alupˇreruˇs´ı bˇehprocesu a vyvol´ase obsluˇzn´afunkce, tzv. handler sign´alu

147 • se sign´alemnen´ısv´az´ana ˇz´adn´ajin´ainformace neˇzˇc´ıslosign´alu,pokud se nepouˇzijePOSIX-1003.1b rozˇs´ıˇren´ı(real-time), viz strana 155.

• po n´avratuz handleru (pokud k nˇemu dojde) proces pokraˇcujeod m´ısta pˇreruˇsen´ı. • historicky sign´alyvznikly jako mechanizmus pro ,,n´asiln´e”ukonˇcen´ıprocesu. Z toho vyplynul i n´azevfunkce kill pro posl´an´ısign´alu. • Sign´alylze zpacov´avat i synchronnˇe,viz sigwait na str. 159.

Posl´an´ısign´alu

int kill(pid t pid, int sig ); • poˇslesign´als ˇc´ıslem sig procesu (nebo skupinˇeproces˚u)podle hodnoty pid: – > 0 . . . procesu s ˇc´ıslempid – == 0 . . . vˇsemproces˚umve stejn´eskupinˇe – == -1 . . . vˇsemproces˚um, kromˇesyst´emov´ych – < -1 . . . proces˚umve skupinˇe abs(pid) • sig == 0 znamen´a,ˇzese pouze zkontroluje opr´avnˇen´ıposlat sign´al,ale ˇz´adn´ysign´alse nepoˇsle. • pr´avo procesu poslat sign´aljin´emu procesu z´avis´ına UID obou proces˚u.

• proces s EUID == 0 m˚uˇzeposlat sign´allibovoln´emu procesu.

• ostatn´ıprocesy: – Linux, Solaris: RUID nebo EUID procesu, kter´yposlal sign´al,se mus´ı shodovat s re´aln´ymUID nebo saved set-user-ID c´ılov´ehoprocesu. – FreeBSD: mus´ıse shodovat EUID obou proces˚u. – IRIX: RUID nebo EUID procesu, kter´yposlal sign´al,se mus´ıshodovat s re´aln´ymnebo efektivn´ımUID nebo saved set-user-ID c´ılov´ehoprocesu.

• pˇr´ıklad(obsahuje i zachycen´ısign´alu,viz dalˇs´ıslajdy) signals/kill.c

• nulov´ysign´allze pouˇz´ıti pro jednoduchou kontrolu existence procesu s dan´ym pid, viz signals/check-existence.c .

148 Oˇsetˇren´ısign´al˚u

• pokud proces neˇreknejinak, provede se v z´avislostina konkr´etn´ımsign´aluimplicitn´ıakce, tj. bud’: – ukonˇcen´ıprocesu (exit) – ukonˇcen´ıprocesu plus coredump (core) – ignorov´an´ısign´alu(ignore) – pozastaven´ıprocesu (stop) – pokraˇcov´an´ıpozastaven´ehoprocesu (continue) • proces tak´em˚uˇze nastavit ignorov´an´ısign´alu • nebo sign´aloˇsetˇren´ıuˇzivatelsky definovanou funkc´ı(handler), po n´avratuz handleru proces pokraˇcujeod m´ıstapˇreruˇsen´ı sign´aly SIGKILL a SIGSTOP vˇzdyvyvolaj´ıimplicitn´ıakci (zruˇsen´ı, resp. pozastaven´ı).

• vytvoˇren´ıcore dumpu znamen´auloˇzen´ıkompletn´ıhoobsahu pamˇetiprocesu do souboru, typicky se jm´enem core • vˇetˇsinasign´al˚uimplicitnˇeukonˇc´ıproces, nˇekter´enav´ıcvytvoˇr´ıjiˇzzmiˇnovan´y core dump, kter´yje moˇzn´en´aslednˇepouˇz´ıtpro ladic´ı´uˇcely.

• d˚uvod toho, proˇcpˇri exec se vˇsechny nastaven´ehandlery sign´al˚unahrad´ı implicitn´ıobsluhou (strana 131) je jasn´y– k´odpˇr´ısluˇsn´ych obluˇzn´ych funkc´ı po vol´an´ı exec pˇrestaneexistovat. • C´ıslasign´al˚uaˇ jejich jm´enolze zjistit pˇrep´ınaˇce -l pˇr´ıkazu kill. Bez dalˇs´ıho argumentu vyp´ıˇseseznam vˇsech sign´al˚uvˇcetnˇeˇc´ısla, pˇripouˇzit´ıˇc´ıseln´eho argumentu vyp´ıˇsen´azevsign´alu:

$ kill -l SIGPIPE 13

• Implicitn´ınastaven´ıakc´ıpro jednotliv´esign´alyje vˇetˇsinoupops´anov manu´alov´e str´ance signal resp. signal.h.

149 Pˇrehled sign´al˚u(1)

sign´alyje moˇzn´elogicky rozdˇelitdo nˇekolika skupin. . . detekovan´echyby:

SIGBUS pˇr´ıstupk nedef. ˇc´astipamˇet’ov´ehoobjektu (core) SIGFPE chyba aritmetiky v pohybliv´eˇc´arce(core) SIGILL nepovolen´ainstrukce (core) SIGPIPE z´apisdo roury, kterou nikdo neˇcte(exit) SIGSEGV pouˇzit´ınepovolen´eadresy v pamˇeti(core) SIGSYS chybn´esyst´emov´evol´an´ı(core) SIGXCPU pˇrekroˇcen´ıˇcasov´eholimitu CPU (core) SIGXFSZ pˇrekroˇcen´ılimitu velikosti souboru (core)

• Generov´an´ıtˇechto sign´al˚uvych´az´ız chyb programu. • Pro sign´aly SIGBUS, SIGFPE, SIGILL a SIGSEGV nen´ı normou pˇresnˇedefi- nov´anapˇr´ıˇcina,ale obvykle jsou to chyby detekovan´ehardwarem. Pˇr´ıklady signals/sigsegv.c , signals/div-by-zero.c .

• Pro tyto ˇctyˇrisign´alytak´eplat´ıtato speci´aln´ıpravidla (podrobnosti viz kapitola 2.4 Signal Concepts v normˇeSUSv3): – Pokud byly nastaven´ejako ignorovan´evol´an´ım sigaction, je chov´an´ı programu po t´e,co je mu takov´ysign´alposl´an,normou nedefinov´ano. – N´avratov´ahodnota handleru nen´ıdefinov´ana. – N´asledeksituace, kdy jeden z tˇechto sign´aluje maskov´anv okamˇziku jeho vygenerovan´ıje nedefinovan´y. • Jin´ymislovy – pokud je hardwarem detekovan´achyba re´aln´a(sign´alnen´ı posl´anpˇres kill a podobn´ymifunkcemi), v´aˇsprogram se pˇrestuto chybu nemus´ıv˚ubec dostat. Nen´ıbezpeˇcn´echybu ignorovat, pokraˇcovat v bˇehu po n´avratuz handleru nebo odd´alitˇreˇsen´ıpomoc´ızamaskov´an´ı.Zachytit tyto sign´alylze, o tom, ˇzeby to bylo jinak, norma nemluv´ı. Pokud tedy m´ate pro tyto sign´alyhandler, je potˇrebapoˇreˇsitdanou situaci jak uzn´ate za vhodn´ea pak ukonˇcitprogram. M˚uˇzeteto vyzkouˇsetna pˇr´ıkladu signals/catch-SIGSEGV.c . Dalˇs´ıinformace vˇcetnˇejin´ehopˇr´ıkladuna vy- zkouˇsen´ıje moˇzn´enal´eztna stranˇe 224. • Pozn´amka: pokud je nˇeconormou nedefinov´ano(undefined), obecnˇeto zna- men´a,ˇzese neoˇcek´av´a,ˇzeby program´atorpotˇreboval zn´atpˇresn´echov´an´ıv

150 takov´esituaci. Pokud je to potˇreba,pravdˇepodobnˇeje ve vaˇsemprogramu nˇecoˇspatnˇe.Jako vˇzdy, urˇciteby se naˇslyvyj´ımkypotvrzuj´ıc´ıpravidlo.

Pˇrehled sign´al˚u(2)

generovan´euˇzivatelem nebo aplikac´ı:

SIGABRT ukonˇcen´ıprocesu (core) SIGHUP odpojen´ıtermin´alu(exit) SIGINT stisk speci´aln´ıkl´avesy Ctrl-C (exit) SIGKILL zruˇsen´ıprocesu (exit, nelze oˇsetˇritani ignorovat) SIGQUIT stisk speci´aln´ıkl´avesy Ctrl-\ (core) SIGTERM zruˇsen´ıprocesu (exit) SIGUSR1 uˇzivatelsky definovan´ysign´al1 (exit) SIGUSR2 uˇzivatelsky definovan´ysign´al2 (exit)

• sign´al SIGHUP se ˇcastopouˇz´ıv´ajako zp˚usob,jak ozn´amitbˇeˇz´ıc´ımu d´emonu, ˇzese zmˇeniljeho konfiguraˇcn´ısoubor a m´asi ho proto znovu naˇc´ıst. • SIGINT a SIGQUIT jsou obvykle generov´any z termin´alu(Ctrl-C a Ctrl-\) a lze je pˇredefinovat pˇr´ıkazem stty nebo pomoc´ıfunkce tcsetattr. Pro to aby se mohl vygenerovat core file je zapotˇreb´ım´ıtto povolen´ev syst´emov´e konfiguraci a limitech, v shellu se toho dos´ahnepˇr´ıkazem ulimit. • vzhledem k tomu, ˇze SIGKILL nelze zachytit, jej pouˇz´ıvejte jen v nutn´ych pˇr´ıpadech; typick´ympˇr´ıpademje to, ˇzebˇeˇz´ıc´ıproces jiˇznelze ukonˇcit jin´ym sign´alem.Mnoho aplikac´ı,hlavnˇed´emon˚u,spol´eh´ana to, ˇzevynucen´eukon- ˇcen´ısign´alemje pˇres SIGTERM. Tento sign´alsi zachyt´ıa provede ukonˇcovac´ı operace – napˇr´ıkladuloˇzen´ıaktu´aln´ıdatab´azena disk, smaz´an´ıdoˇcasn´ych soubor˚uapod. Pouˇz´ıvat rovnou SIGKILL proto, ˇzeproces to “vˇzdycky zabije”, je neznalost vˇeci,kter´ase v´amm˚uˇzedost vymst´ıt. • uk´azka na SIGQUIT na Solarisu:

$ sleep 10 ^\Quit (core dumped) $ mdb core Loading modules: [ libc.so.1 ld.so.1 ] > $c libc.so.1‘__nanosleep+0x15(8047900, 8047908)

151 libc.so.1‘sleep+0x35(a) main+0xbc(2, 8047970, 804797c) _start+0x7a(2, 8047a74, 8047a7a, 0, 8047a7d, 8047b91) >

• SIGTERM je defaultn´ısign´alpro pˇr´ıkaz kill(1) • SIGUSR1 a SIGUSR2 nejsou pouˇzity ˇz´adn´ymsyst´emov´ymvol´an´ıma jsou plnˇe k dispozici uˇzivateli

Pˇrehled sign´al˚u(3)

job control:

SIGCHLD zmˇenastavu synovsk´ehoprocesu (ignore) SIGCONT pokraˇcov´an´ıpozastaven´eho procesu (continue) SIGSTOP pozastaven´ı(stop, nelze oˇsetˇritani ignorovat) SIGTSTP pozastaven´ız termin´alu Ctrl-Z (stop) SIGTTIN ˇcten´ız termin´alu procesem na pozad´ı(stop) SIGTTOU z´apisna termin´alprocesem na pozad´ı(stop) • souˇc´ast´ınepovinn´ehoPOSIX rozˇs´ıˇren´ı,existuj´ıpouze kdyˇzv je definov´anomakro POSIX JOB CONTROL

• plat´ı,ˇzenikdy nen´ıpovoleno v´ıceproces˚umnajednou ˇc´ıstz kontroln´ıhoter- min´alu,ale v´ıceproces˚unajednou m˚uˇzena termin´alzapisovat.

• pozastaven´ıskupiny proces˚uspustˇen´ez termin´alu(ˇcastopˇres Ctrl-Z) se pro- v´ad´ısign´alem SIGTSTP, ne SIGSTOP; aplikace tedy tento sign´alm˚uˇzezachytit.

152 Pˇrehled sign´al˚u(4)

ˇcasovaˇce: SIGALRM pl´anovan´eˇcasov´epˇreruˇsen´ı(exit) SIGPROF vyprˇsen´ıprofiluj´ıc´ıhoˇcasovaˇce(exit) SIGVTALRM vyprˇsen´ıvirtu´aln´ıhoˇcasovaˇce(exit) r˚uzn´e: SIGPOLL testovateln´aud´alost(exit) SIGTRAP ladic´ıpˇreruˇsen´ı(core) SIGURG urgentn´ıud´alostna soketu (ignore)

• SIGALRM a souvisej´ıc´ıfunkce alarm se pouˇz´ıvaj´ıpro odmˇeˇrov´an´ıˇcasov´ych interval˚uv uˇzivatelsk´emprocesu (napˇr.pˇriimplementaci timeout˚u).

153 Nastaven´ıobsluhy sign´al˚u

int sigaction(int sig, const struct sigaction *act, struct sigaction *oact ); • nastav´ıobsluhu sign´alu sig podle act a vr´at´ıpˇredchoz´ı nastaven´ıv oact. • obsah struktury sigaction: – void (*sa handler )(int) ... SIG DFL, SIG IGN, nebo adresa handleru – sigset t sa mask . . . sign´alyblokovan´ev handleru, nav´ıc je blokov´ansign´al sig – int sa flags ... SA RESETHAND (pˇrivstupu do handleru nastavit SIG DFL), SA RESTART (restartovat pˇreruˇsen´a syst´emov´avol´an´ı), SA NODEFER (neblokovat sign´al sig bˇehemobsluhy)

• kdyˇzje act == NULL, pouze se zjist´ınastaven´ıobsluhy, nemˇen´ıse. Jestliˇze n´aspˇredchoz´ınastaven´ınezaj´ım´a,lze pouˇz´ıt oact == NULL. • pokud nen´ınastaveno SA RESTART, syst´emov´avol´an´ıaktivn´ıv bodˇepˇr´ıchodu sign´aluskonˇc´ıs chybou EINTR. Restartov´an´ınemus´ıfungovat pro vˇsechna syst´emov´avol´an´ı, napˇr.na FreeBSD je select pˇreruˇsensign´alemvˇzdy, i kdyˇzje nastaveno SA RESTART (pozn: nemus´ıb´ytpravda u souˇcasn´ych verz´ı, nezkouˇseljsem to na nich). • pozor na probl´emvz´ajemn´ehovylouˇcen´ımezi procesem a handlerem, popˇr. mezi handlery pro r˚uzn´esign´aly. Jestliˇzeje nastaveno SA NODEFER, mˇelby b´ythandler reentrantn´ı.

• v handleru sign´aluby se mˇelypouˇz´ıvat pouze funkce, kter´ejsou pro takov´epouˇzit´ıbezpeˇcn´e. Mus´ıbud’ b´ytreentrantn´ı, nebo je nutn´e zajistit, aby nepˇriˇsel sign´alv nevhodnou dobu (napˇr.uvnitˇrfunkce pˇrijde sign´al,v jehoˇzhandleru se vol´astejn´afunkce). Minim´aln´ıskupina funkc´ı, kter´emus´ıb´yttzv. async-signal-safe, je vyjmenov´anav SUSv3 v sekci System Interfaces: General Information ⇒ Signal Concepts ⇒ Signal Acti- ons (2.4.3). Jednotliv´esyst´emy mohou samozˇrejmˇedefinovat i dalˇs´ıtakov´e funkce. Zda funkce je nebo nen´ı bezpeˇcnˇepouˇziteln´av handleru by mˇelo b´ytjasn´ez manu´alov´estr´anky;na Solarisu je tato informace vˇzdyv sekci ATTRIBUTES. • proˇcm˚uˇzenastat probl´em,kdyˇzpouˇzijete v handleru sign´alujinou funkci neˇzasync-signal-safe? Je to jednoduch´e– pˇredstavte si, ˇzekdyˇzprogram vykon´av´afunkci, kter´anen´ıasync-signal-safe, pˇrijdesign´ala v handleru se

154 vyvol´afunkce stejn´a.Pokud funkce nen´ı pro takov´epouˇzit´ı napsan´a,tak m˚uˇzedoj´ıt napˇr´ıklad k nekonzistenci statick´ych dat ve funkci pouˇzit´ych, pˇr´ıpadnˇek uv´aznut´ı(dead lock) apod. Pr´avˇekv˚ulitomu, ˇzev handlerech lze bezpeˇcnˇepouˇz´ıtjen podmnoˇzinu existuj´ıc´ıch vol´an´ı,se v handleru ˇcasto pouze nastav´ıglob´aln´ıpromˇenn´aoznaˇcuj´ıc´ıpˇr´ıchod pˇr´ısluˇsn´ehosign´alua ta se n´aslednˇetestuje, napˇr´ıkladv cyklu serveru, kter´yvyˇrizujepoˇzadavky nebo programu kter´yzpracov´av´aud´alosti.Zpomalen´ıobsluhy sign´aluje minim´aln´ı, protoˇzefunkce kter´aˇcek´ana dalˇs´ıpoˇzadavek je typicky pˇreruˇsiteln´asign´alem a v takov´em pˇr´ıpadˇe ihned vrac´ı EINTR. N´asledujekontrola glob´aln´ı(ch) promˇenn´e(´ych) na to, zda byl pˇrijmut nˇejak´ysign´al.Viz pˇr´ıklad signals/event-loop.c .

• funkce sigaction je obecnˇejˇs´ıneˇzstarˇs´ıfunkce signal a sigset, kter´ezde ani nezmiˇnuji.Doporuˇcujipouˇz´ıvat pouze sigaction. Pouˇzit´ı signal nen´ı napˇr´ıkladspr´avn´es vl´akny, viz specifikace: “Use of this function is unspecified in a multi-threaded process.”

• Pozor na to, ˇzechov´an´ıfunkce signal() se m˚uˇzeliˇsitpodle syst´emu. Na- pˇr´ıkladna FreeBSD z˚ust´av´ahandler st´alenastaven, na Solarisu je z d˚uvodu zachov´an´ı zpˇetn´ekompatibility handler pˇredjeho vyvol´an´ım resetov´anna SIG DFL. Funkce pˇr´ıznaku SA RESETHAND je pr´avˇeto, aby bylo moˇzn´esimu- lovat p˚uvodn´ıchov´an´ıfunkce signal(), kter´eb´yv´aimplementov´anopomoc´ı syst´emov´ehovol´an´ı sigaction(). Pˇr´ıkladna rozd´ılmezi funkcemi signal() a sigaction(): signal/signal-vs-sigaction.c .

• (nebudete nejsp´ıˇspotˇrebovat) pro v´yskok z handleru sign´alujinam neˇzna m´ıstovzniku sign´aluse daj´ıpouˇz´ıtfunkce sigsetjmp a siglongjmp. Pozor na to, ˇzev tomto pˇr´ıpadˇesi mus´ımeb´ytjisti, ˇzev okamˇzikupˇr´ıchodu sign´alu nen´ıprogram uvnitˇrne-reentrantn´ıfunkce. V´yskokem z handleru do hlavn´ıho programu nen´ıvykon´av´an´ıtakov´efunkce ukonˇcenoa mohou nastat stejn´e probl´emy jako pˇrivol´an´ıne-reentrantn´ıfunkce pˇr´ımoz handleru.

• pokud syst´empodporuje ˇc´astPOSIX.1b zvanou Realtime Signals Extension (RTS), je moˇzn´epˇr´ıznakem SA SIGINFO toto rozˇs´ıˇren´ıpouˇz´ıt.V tom pˇr´ıpadˇe se pouˇzije jin´apoloˇzka struktury sigaction pro ukazatel na handler, a tou je sa sigaction. Tento handler m´ajiˇz3 parametry a je moˇzn´ezjis- tit napˇr´ıklad to, kter´yproces sign´alposlal, pod jak´ymuˇzivatelem proces bˇeˇzela mnoho dalˇs´ıch informac´ı.Z´ajemceodkazuji na manu´alovou str´anku signal.h(3HEAD) na Solarisu, specifikaci tohoto hlaviˇckov´ehosouboru pˇr´ımo v SUSv3 nebo na knihu [POSIX.4], strana5. Dalˇs´ıinformace jsou tak´ena stran´ach 15a 159. Pˇr´ıklady: signals/siginfo.c , signals/sigqueue.c .

155 Pˇr´ıklad:ˇcasovˇeomezen´yvstup

void handler(int sig) { write(2," !!! TIMEOUT !!! \n", 17); }

int main(void) { char buf[1024]; struct sigaction act; int sz; act.sa handler = handler; sigemptyset(&act.sa mask); act.sa flags = 0; sigaction(SIGALRM, &act, NULL); alarm(5); sz = read(0, buf, 1024); alarm(0); if (sz > 0) write(1, buf, sz); return (0); }

• lze pouˇz´ıvat i ˇcasovaˇces jemnˇejˇs´ımrozliˇsen´ımneˇz1 s. Nastavuj´ıa testuj´ı se funkcemi setitimer a getitimer. Pˇrivyprˇsen´ıpos´ılaj´ısign´alyprocesu, kter´yˇcasovaˇcenastavil podle prvn´ıhoargumentu which:

– ITIMER REAL . . . mˇeˇr´ıre´aln´yˇcas,pos´ıl´a SIGALRM – ITIMER VIRTUAL . . . mˇeˇr´ı virtu´aln´ıˇcas(pouze ˇcas,kdy proces bˇeˇz´ı), pos´ıl´a SIGVTALRM – ITIMER PROF . . . mˇeˇr´ı virtu´aln´ıˇcasa ˇcas,kdy syst´embˇeˇz´ı na konto procesu, pos´ıl´a SIGPROF • pozn: vˇsimˇetesi, ˇzeaˇckoliv by to sv´adˇelopouˇz´ıtpro tisk hl´aˇskyv pˇr´ıkladu funkci fprintf apod., nemusel by to b´ytdobr´yn´apad,protoˇzenemus´ıb´yt bezpeˇcn´apro pouˇzit´ıv handleru sign´alu,viz strana 154.

• pˇr´ıklad: signals/alarm.c

156 Blokov´an´ısign´al˚u

• blokovan´esign´alybudou procesu doruˇceny a zpracov´any aˇzpo odblokov´an´ı.

int sigprocmask(int how, const sigset t *set, sigset t *oset ); • nastav´ımasku blokovan´ych sign´al˚ua vr´at´ıstarou masku. • how – SIG BLOCK pro pˇrid´an´ısign´al˚uco se maj´ıblokovat, pro odebr´an´ı SIG UNBLOCK, pro kompletn´ızmˇenu masky SIG SETMASK • pro manipulaci s maskou sign´al˚uslouˇz´ıfunkce: sigaddset(), sigdelset(), sigemptyset(), sigfillset(), sigismember() int sigpending(sigset t *set ); • vr´at´ıˇcekaj´ıc´ızablokovan´esign´aly.

• Je rozd´ılmezi ignorov´an´ıma blokov´an´ımsign´alu.Ignorovan´ysign´alj´adro zahod´ıa proces ho nedostane, blokovan´ysign´alproces dostane po jeho od- blokov´an´ı. • Z´avis´ına implementaci, zda pˇriv´ıcen´asobn´emdoruˇcen´ıstejn´ehosign´alupro- cesu, kter´ym´atento sign´alzablokovan´y,bude sign´alpo odblokov´an´ıoˇsetˇren jednou nebo v´ıcekr´at. • V pˇr´ıpadˇerozˇs´ıˇren´ı sign´al˚uz POSIX.4 (strana 155), tj. pouˇzit´ı pˇr´ıznaku SA SIGINFO, jsou sign´alydoruˇcovan´epˇresfrontu a tedy se ˇz´adn´yn´asobn´y v´yskytstejn´ehosign´aluneztrat´ı.

• Argument oset pro z´ısk´an´ıp˚uvodn´ımasky m˚uˇzeb´yt NULL, stejnˇejako m˚uˇze b´ytnastaven´yna NULL i parametr druh´y,tj. set. Ve speci´aln´ımpˇr´ıpadˇe,kdy jsou oba parametry nulov´e,funkce sigprocmask nedˇel´anic.

157 Pˇr´ıklad:blokov´an´ısign´al˚u

sigset t sigs, osigs; struct sigaction sa; sigfillset(&sigs); sigprocmask(SIG BLOCK, &sigs, &osigs); switch(cpid = fork()) { case -1: /* Chyba */ sigprocmask(SIG SETMASK, &osigs, NULL); ... case 0: /* Synovsk´yproces */ sa.sa handler = h cld; sigemptyset(&sa.sa mask); sa.sa flags = 0; sigaction(SIGINT, &sa, NULL); sigprocmask(SIG SETMASK, &osigs, NULL); ... default: /* Rodiˇcovsk´yproces */ sigprocmask(SIG SETMASK, &osigs, NULL); ... }

• pˇr´ıkladukazuje situaci, kdy proces vytv´aˇr´ıpotomky pomoc´ı fork a je potˇreba, aby potomci mˇelijin´yhandler sign´al˚uneˇzrodiˇcovsk´yproces. Funguje to proto, ˇzevol´an´ı fork nemˇen´ımasky sign´al˚u,viz strana 130. • pro jednoduchost v pˇr´ıkladublokuji vˇsechny sign´aly, i kdyˇzna stran´ach 150 a 224 je vysvˇetleno,proˇcto nen´ıspr´avn´epouˇzit´ımaskov´an´ı.

• blokov´an´ıje vhodn´epouˇz´ıttam, kde oˇsetˇren´ıpˇreruˇsen´ıuprostˇredposloup- nosti operac´ı by bylo pˇr´ıliˇssloˇzit´e,nebo kde korektn´ı oˇsetˇren´ı nen´ı jinak moˇzn´e.V uveden´empˇr´ıkladˇeby bez blokov´an´ısign´al˚umohl synovsk´yproces dostat sign´aldˇr´ıv, neˇzstihne zmˇenithandler.

• dalˇs´ıpˇr´ıkladje proces, kter´ypˇrivyprˇsen´ıtimeoutu pˇreruˇs´ıprov´adˇenoupo- sloupnost operac´ıvol´an´ım siglongjmp zevnitˇrhandleru sign´alu.Je potˇreba zablokovat sign´al SIGALRM bˇehemprov´adˇen´ıatomick´ych podposloupnost´ı(tj. takov´ych, kter´ese mus´ıprov´estbud’ cel´e,nebo v˚ubec ne).

158 Cek´an´ınaˇ sign´al

int pause(void); • pozastav´ıvolaj´ıc´ıproces do pˇr´ıchodu (neblokovan´eho)sign´alu int sigsuspend(const sigset t *sigmask ); • jako pause(), ale nav´ıcpo dobu ˇcek´an´ımasku blokovan´ych sign´al˚uzmˇen´ına sigmask int sigwait(const sigset t *set, int *sig ); • ˇcek´ana pˇr´ıchod sign´aluz mnoˇziny set (tyto sign´alymus´ıb´yt pˇredt´ımzablokovan´e),ˇc´ıslosign´aluvr´at´ıv sig. Vrac´ı0 nebo ˇc´ıslochyby. • nevol´ase handler sign´alu(to ale nen´ıv normˇejednoznaˇcnˇe definov´ano)

• Neblokovan´ysign´alv pause a sigsuspend vyvol´ahandler a po jeho skonˇcen´ı program opust´ı sign´alzachycuj´ıc´ı funkci a pokraˇcujed´ale.Pokud m´aale sign´alproces ukonˇcit(napˇr.nemaskovan´y SIGTERM bez handleru), stane se tak. • Pomoc´ıtˇechto funkc´ıa blokov´an´ısign´al˚use implementuje synchronn´ıobsluha sign´al˚u.Proces nejprve zablokuje sign´aly, kter´eho zaj´ımaj´ı,a pak na nˇeve vhodn´ych chv´ıl´ıch bud’ ˇcek´a,nebo jen testuje (pomoc´ı sigpending), zda sign´alpˇriˇsel,a pokud ne, pokraˇcujed´al.

• Funkce sigwait byla pˇrid´anas POSIX-1003.1c rozˇs´ıˇren´ım (vl´akna)a je to “jedin´y”spr´avn´yzp˚usob,jak obsluhovat asynchronn´ı sign´alyv multi- vl´aknov´eaplikaci. To ˇzebyla pˇrid´anas vl´akny je potvrzeno i t´ım,ˇzev pˇr´ıpadˇe probl´em˚uvrac´ıpˇr´ımoˇc´ıslochyby.

• Existuj´ıi pˇr´ıbuzn´epodobnˇese jmenuj´ıc´ıfunkce sigwaitinfo a sigtimedwait, definovan´es rozˇs´ıˇren´ımPOSIX-1003.1b (real-time). Funguj´ına podobn´em principu, ale na rozd´ılod sigwait pracuj´ıs errno a je z nich moˇzn´ez´ıskat v´ıceinformac´ıd´ıkystruktuˇre siginfo t, viz strana 155. Je tedy moˇzn´eje pouˇz´ıtm´ısto sigwait. • Pˇr´ıklad(sign´alse pouˇzijepro synchronizaci dvou proces˚ukomunikuj´ıc´ıch pˇres sd´ılenoupamˇet’): signals/sigwait.c

• Pozor na to, ˇzebyste nemˇelitento zp˚usobobsluhy sign´al˚upouˇz´ıvat pro sig- n´alysynchronn´ıjako jsou SIGSEGV, SIGILL, apod. V´ıcese doˇctete na stran´ach 150a 224.

159 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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

160 Probl´em:konflikt pˇrisd´ılen´ıdat

• m´amestrukturu struct { int a, b; } shared ; • for( ; ; ) { /* neatomick´aoperace */ a = shared.a; b = shared.b; if (a != b) printf("NEKONZISTENTNI´ STAV"); /* neatomick´aoperace */ shared.a = val; shared.b = val; } • jestliˇzetento cyklus spust´ımeve dvou r˚uzn´ych procesech (nebo vl´aknech), kter´eobˇesd´ılej´ıstejnou strukturu shared a maj´ı r˚uzn´ehodnoty val, bude doch´azetke konflikt˚um. • pˇr´ıˇcina:operace na zv´yraznˇen´ych ˇr´adc´ıch nejsou atomick´e.

• ani operace, kterou lze v C zapsat jedn´ımpˇr´ıkazem, nemus´ıb´ytatomick´a. Pˇr.:na RISCov´ych procesorech se pˇr´ıkaz a++ typicky pˇreloˇz´ıjako sekvence:

load reg,[a] inc reg store [a],reg

a to z toho d˚uvodu, ˇzena t´etoarchitektuˇrenelze inkrementovat ˇc´ıslopˇr´ımov pamˇeti.Pro tyto pˇr´ıpadym´anapˇr´ıkladSolaris sadu funkc´ı atomic add(3c), jejichˇzpouˇzit´ıje mnohem rychlejˇs´ıneˇzklasick´ezamykac´ımechanismy. V´ıce viz strana 235.

• obecnˇeobdobn´yprobl´emnast´av´a,kdyˇzv´ıceproces˚usd´ıl´ınˇejak´ysyst´emov´y zdroj.

• pˇr´ıklad: race/race.c

161 Sc´en´aˇrkonfliktu

Procesy A(val==1) a B(val==2) a b 1. poˇc´ateˇcn´ıstav struktury ? ? 2. proces A zap´ıˇsedo poloˇzky a 1 ? 3. proces B zap´ıˇsedo poloˇzky a 2 ? 4. proces B zap´ıˇsedo poloˇzky b 2 2 5. proces A zap´ıˇsedo poloˇzky b 2 1 6. struktura je v nekonzistentn´ım stavu a jeden z proces˚uto zjist´ı.

• dalˇs´ımoˇznost:

1. struktura je v konzistentn´ımstavu, napˇr. (1, 1) 2. proces B zap´ıˇse 2 do poloˇzky a 3. proces A pˇreˇctehodnotu struktury (2, 1) dˇr´ıve, neˇzproces B stihne zapsat poloˇzku b • pozor na to, ˇzesynchronizaˇcn´ıprobl´emy se ˇcastoprojev´ıaˇzna v´ıceprocesorov´em stroji, nebo na v´ıceprocesorech neˇzkolik jich m´atepˇriv´yvoji k dispozici apod. Je tˇrebana to myslet pˇritestov´an´ı.

162 Reˇsen´ı:vz´ajemn´evylouˇcen´ıproces˚uˇ

• je potˇrebazajistit atomicitu operac´ınad strukturou, tzn. jeden proces prov´ad´ımodifikaci a dokud neuvede strukturu do konzistentn´ıhostavu, druh´yproces s n´ınem˚uˇzemanipulovat.

Procesy A(val==1) a B(val==2) a b 1. poˇc´ateˇcn´ıstav struktury ? ?  2. proces A zap´ıˇsedo poloˇzky a 1 ?  3. proces B mus´ıˇcekat 1 ?  4. proces A zap´ıˇsedo poloˇzky b 1 1  5. proces B zap´ıˇsedo poloˇzky a 2 1 6. proces B zap´ıˇsedo poloˇzky b 2 2 7. Struktura je v konzistentn´ımstavu.

• je tˇrebazajistit vz´ajemn´evylouˇcen´ıi pˇriˇcten´ı,aby ˇctouc´ıproces nepˇreˇcetl nekonzistentn´ıobsah struktury uprostˇredzmˇen.Pˇriz´apisuje nutn´evylouˇcit vˇsechny ostatn´ıprocesy, ale pˇriˇcten´ıstaˇc´ıvylouˇcitjen z´apis,souˇcasn´eˇcten´ı v´ıceprocesy nevad´ı. • kritick´asekce je kus k´odu,kter´yby mˇelprov´adˇetpouze jeden proces nebo vl´akno,jinak m˚uˇzedoj´ıt k nekonzistenc´ım; napˇr´ıkladˇspatnˇepospojovan´y v´azan´yseznam, neodpov´ıdaj´ıc´ısi indexy v datab´aziapod. Je moˇzn´eto defi- novat i tak, ˇzekritick´asekce je k´od,kter´ypˇristupujek nebo modifikuje bl´ıˇze neurˇcen´yzdroj sd´ılen´yv´ıceprocesy nebo vl´akny a proto je nutn´epˇr´ıstupk takov´emu k´odusynchronizovat. Kritick´asekce by mˇelab´ytco nejkratˇs´ı,aby ostatn´ıprocesy (vl´akna)ˇz´adaj´ıc´ıo vstup do t´etosekce ˇcekaly co nejkratˇs´ı moˇznoudobu. Druh´adefinice je o nˇecoobecnˇejˇs´ı,protoˇzese do n´ıvejdou i situace, kdy pouze jeden proces nebo vl´aknom˚uˇzestav mˇenit,ale pokud se tak nedˇeje,m˚uˇzev´ıceproces˚uˇcivl´aken dan´ystav ˇc´ıst,to znamen´aˇzek´od kritick´esekce za jist´ych pˇresnˇedefinovan´ych podm´ınekm˚uˇzevykon´avat v´ıce proces˚unebo vl´aken najednou.

163 Probl´em:konflikt zapisovatel˚ua ˇcten´aˇr˚u

• nˇekolik bˇeˇz´ıc´ıch proces˚uzapisuje protokol o sv´eˇcinnostido spoleˇcn´eholog-souboru. Nov´yz´aznamje pˇripojen vˇzdyna konec souboru. • pokud z´apisz´aznamu nen´ıproveden atomickou operac´ı,m˚uˇze doj´ıtk prom´ıch´an´ıv´ıce souˇcasnˇezapisovan´ych z´aznam˚u. • zapisovat sm´ıvˇzdypouze jeden proces. • dalˇs´ıprocesy ˇctoudata z log-souboru. • pˇripˇreˇcten´ıpr´avˇezapisovan´eho z´aznamu obdrˇz´ımenespr´avn´a (ne´upln´a)data. • bˇehemoperace z´apisuze souboru nelze ˇc´ıst.Kdyˇznikdo nezapisuje, m˚uˇzev´ıceproces˚uˇc´ıstsouˇcasnˇe.

• povoleny jsou tedy 2 situace: jeden zapisovatel nebo v´ıceˇcten´aˇr˚u • na lok´aln´ımdisku lze pro synchronizaci zapisovatel˚upouˇz´ıtˇreˇsen´ıpomoc´ı pˇr´ıznaku O APPEND, kter´eale nebude fungovat napˇr. na vzd´alen´emdisku pˇr´ıstupn´empˇresNFS nebo v pˇr´ıpadˇe,ˇzez´apisjedn´elogovac´ızpr´avyje prove- den v´ıceneˇzjedn´ımvol´an´ım write(). Nav´ıcto neˇreˇs´ısynchronizaci ˇcten´aˇr˚u – lze ˇc´ısti v pr˚ubˇehu z´apisu.

164 Reˇsen´ı:zamyk´an´ısoubor˚uˇ

• zapisuj´ıc´ıproces zamkne soubor pro z´apis.Ostatn´ıprocesy (zapisovatel´ei ˇcten´aˇri)se souborem nemohou pracovat a mus´ı ˇcekat na odemˇcen´ız´amku. • ˇctouc´ıproces zamkne soubor pro ˇcten´ı.Zapisovatel´emus´ıˇcekat na odemˇcen´ız´amku, ale ostatn´ıˇcten´aˇrimohou tak´ezamknout soubor pro ˇcten´ıa ˇc´ıstdata. • v jednom okamˇzikum˚uˇzeb´ytna souboru aktivn´ınejv´yˇse jeden z´amekpro z´apisnebo libovolnˇemnoho z´amk˚upro ˇcten´ı,ale ne oba typy z´amk˚usouˇcasnˇe. • z d˚uvodu efektivity by kaˇzd´yproces mˇel drˇzetz´amekco nejkratˇs´ıdobu a pokud moˇznonezamykat cel´ysoubor, ale jen ´usek,se kter´ympracuje. Preferovan´eje pasivn´ıˇcek´an´ı,aktivn´ı ˇcek´an´ıje vhodn´ejen na velmi kr´atkou dobu.

• dva zp˚usoby ˇcek´an´ı: aktivn´ı(busy waiting) – proces v cyklu testuje podm´ınku,na kterou ˇcek´a, dokud nen´ısplnˇena pasivn´ı – proces se zaregistruje v j´adrujako ˇcekaj´ıc´ına podm´ınkua pak se usp´ı,j´adroho probud´ı,kdyˇzdojde ke splnˇen´ıpodm´ınky

• aktivn´ıˇcek´an´ıje ospravedlniteln´epouze ve speci´aln´ıch situac´ıch. Na takov´esi- tuace asi v z´apoˇctov´emprogramu nenaraz´ıtea urˇcitˇene v pˇr´ıkladuu zkouˇsky. Pouˇzit´ıaktivn´ıhoˇcek´an´ıv takov´empˇr´ıpadˇeautomaticky znamen´a nesplnˇen´ızad´an´ıp´ısemky.

165 Synchronizaˇcn´ımechanismy • teoretick´eˇreˇsen´ı– algoritmy vz´ajemn´ehovylouˇcen´ı(Dekker 1965, Peterson 1981) • z´akaz pˇreruˇsen´ı(na 1 CPU stroji), speci´aln´ı test-and-set instrukce • lock-soubory • n´astroje poskytovan´eoperaˇcn´ımsyst´emem – semafory (souˇc´astSystem V IPC) – z´amkypro soubory (fcntl(), flock()) – synchronizace vl´aken: mutexy (ohraniˇcuj´ıkritick´esekce, pouze jedno vl´aknom˚uˇzedrˇzetmutex), podm´ınkov´e promˇenn´e (zablokuj´ıvl´akno,dokud jin´evl´akno nesignalizuje zmˇenu podm´ınky), read-write z´amky (sd´ılen´ea exkluzivn´ız´amky, podobnˇejako pro soubory)

• Dekker i Peterson potˇrebuj´ık dosaˇzen´ıpoˇzadavan´ehov´ysledku pouze sd´ılenou pamˇet’, tj. nˇekolik promˇenn´ych sd´ılen´ych obˇemaprocesy. • Dekkerovo ˇreˇsen´ıse ud´av´ajako prvn´ıˇreˇsen´ıprobl´emu vz´ajemn´ehovylouˇcen´ı dvou proces˚u,aniˇzby bylo nutn´eaplikovat naivn´ıalgoritmus striktn´ıhostˇr´ı- d´an´ı,tj. pokud druh´yproces nevykazoval z´ajemo vstup do kritick´esekce, mohl tam prvn´ı(a naopak) proces vstoupit tolikr´atza sebou, kolikr´atchtˇel. Dekkerovo ˇreˇsen´ınen´ıv˚ubec trivi´aln´ı,porovnejte s o 16 let mladˇs´ımˇreˇsen´ım Petersonov´ym,napˇr´ıkladna en.wikipedia.org (hledejte “Dekker’s algori- thm”, “Peterson’s algorithm”) • my se nebudeme zab´yvat teoretick´ymialgoritmy vz´ajemn´ehovylouˇcen´ıani nebudeme popisovat hardwarov´emechanismy pouˇz´ıvan´ej´adrem.Zamˇeˇr´ıme se pouze na pouˇzit´ılock soubor˚u(kter´evyuˇz´ıvaj´ıatomiˇcnostinˇekter´ych sou- borov´ych operac´ı) a speci´aln´ıch synchronizaˇcn´ıch n´astroj˚uposkytovan´ych j´adrem. • podm´ınkov´epromˇenn´e= conditional variables

166 Lock-soubory • pro kaˇzd´ysd´ılen´yzdroj existuje dohodnut´ejm´enosouboru. Zamˇcen´ızdroje se provede vytvoˇren´ımsouboru, odemˇcen´ı smaz´an´ımsouboru. Kaˇzd´yproces mus´ıotestovat, zda soubor existuje, a pokud ano, tak poˇckat. void lock(char *lockfile) { while( (fd = open(lockfile, O RDWR|O CREAT|O EXCL, 0600)) == -1) sleep(1); /* Cek´ameveˇ smyˇccena odemˇcen´ı*/ close(fd); }

void unlock(char *lockfile) { unlink(lockfile); }

• kl´ıˇcemk ´uspˇechu je samozˇrejmˇepouˇzit´ıflagu O EXCL

• pˇr´ıklad: file-locking/lock-unlock.c , a pouˇzijtespoleˇcnˇese shellov´ym skriptem file-locking/run.sh .

• pˇrihav´ariiprocesu nedojde ke zruˇsen´ıpˇr´ıpadn´ych z´amk˚ua ostatn´ıprocesy by ˇcekaly vˇeˇcnˇe.Proto je vhodn´esi do lock-souboru poznamenat PID pro- cesu, kter´yz´amekvytvoˇril.Proces, kter´yˇcek´ana odemˇcen´ı,m˚uˇzetestovat, zda proces, kter´emu z´amekpatˇr´ı, st´alebˇeˇz´ı. Kdyˇzne, lze z´amekzruˇsita znovu zkusit vytvoˇrit.User level pˇr´ıkaz kter´ytoto um´ıa dovoluje pouˇz´ıvat lock soubory z shellov´ych skript˚uje napˇr´ıklad shlock(1) (na FreeBSD v /usr/ports/sysutils/shlock), teoreticky by vˇsakmohl zp˚usobitsituaci z n´asleduj´ıc´ıhoodstavce. • pozor: jestliˇzev´ıceproces˚unajednou zjist´ı,ˇzeproces drˇz´ıc´ız´amekuˇznee- xistuje, m˚uˇzedoj´ıtk n´asleduj´ıc´ıchybˇe.Prvn´ıproces smaˇzez´ameka znovu ho vytvoˇr´ıse sv´ymPID. Dalˇs´ıproces udˇel´atot´eˇz,protoˇze operace pˇreˇcten´ı obsahu souboru a jeho n´asledn´ehosmaz´an´ınen´ıatomick´a.Ted’ si ale oba procesy mysl´ı,ˇzez´ıskaly z´amek! • probl´em: funkce lock() obsahuje aktivn´ıˇcek´an´ına uvolnˇen´ız´amku.Lze ˇreˇsitnapˇr.tak, ˇzeproces, kter´yz´ısk´az´amek,otevˇrepro z´apispojmenovanou rouru. Cekaj´ıc´ıprocesyˇ se usp´ıt´ım,ˇzezkus´ıˇc´ıstz roury. Souˇc´ast´ı unlock() bude i zavˇren´ıroury a t´ımuvolnˇen´ıˇcekaj´ıc´ıch proces˚u. Upozorˇnujina to, ˇzezkouˇskov´epˇr´ıkladypro zad´an´ıobsahuj´ıc´ıjakoukoli synchronizaci nejsou akceptov´any jako spr´avn´e,pokud je jakkoli pouˇzitoaktivn´ı ˇcek´an´ı,vˇcetnˇeuk´azan´ehoˇreˇsen´ıtypu sleep(1) volan´ehove smyˇcce.

167 • lock soubory se v praxi vˇetˇsinoupouˇz´ıvaj´ıpouze pro situace, kdy se napˇr´ıklad hl´ıd´an´asobn´espuˇstˇen´ı t´eˇzeaplikace. Ze zkuˇsenostiradˇejiopˇetupo- zorˇnuji,ˇzepokud je bude student na zkouˇscepouˇz´ıvat napˇr´ıklad pro synchronizaci vl´aken, neuspˇeje.

Zamyk´an´ısoubor˚u: fcntl()

int fcntl(int fildes, int cmd, ...); • k nastaven´ız´amk˚upro soubor fildes se pouˇz´ıv´a cmd: – F GETLK . . . vezme popis z´amkuz tˇret´ıhoargumentu a nahrad´ıho popisem existuj´ıc´ıhoz´amku,kter´ys n´ımkoliduje – F SETLK . . . nastav´ınebo zruˇs´ız´amekpopsan´ytˇret´ım argumentem, pokud nelze z´ameknastavit, ihned vrac´ı −1 – F SETLKW . . . jako F SETLK, ale usp´ıproces, dokud nen´ı moˇzn´enastavit z´amek(W znamen´a“wait”) • tˇret´ıargument obsahuje popis z´amkua je typu ukazatel na struct flock

• zamyk´an´ısoubor˚usd´ılen´ych pˇresNFS zajiˇst’uje d´emon lockd. • z´amkyjsou obecnˇedvou typ˚u: advisory locks – pro spr´avnoufunkci mus´ı vˇsechny procesy pracuj´ıc´ı se z´amˇcen´ymisoubory kontrolovat z´amkypˇredˇcten´ımnebo z´apisemsou- boru; jsou v´ıcepouˇz´ıvan´e mandatory locks – jestliˇzeje na souboru z´amek,budou ˇctec´ıa z´apisov´e operace se souborem automaticky zablokov´any, tj. z´amekse uplatn´ıi v procesech, kter´eho explicitnˇenekontroluj´ı – nedoporuˇcuj´ıse, ne vˇzdyfunguj´ı(napˇr. lockd implementuje pouze advisory locking) – pro urˇcit´ysoubor se zapne nastaven´ımbitu SGID a zruˇsen´ımpr´ava spuˇstˇen´ıpro skupinu (tj. nastaven´ı,kter´ejinak nem´avelk´ysmysl - m´ıtset GID executable bit na souboru, kter´ynen´ıspustiteln´y). Funguje to tak, ˇzejeden proces si vezme z´amekna dan´emsouboru (napˇr.pomoc´ı fcntl). Dalˇs´ıprocesy pak nemus´ıexplicitnˇezamy- kat, protoˇzekaˇzdouoperaci open/read/write s dan´ymsouborem kontroluje kernel proti z´amk˚umna souboru a vynut´ıˇcek´an´ıaˇzdo chv´ılekdy je z´amekexplicitnˇeprvn´ıprocesem uvolnˇen. Syst´em,kter´ymandatory locking implementuje, je napˇr´ıkladSolaris

168 nebo Linux, FreeBSD tuto vlastnost naopak nepodporuje. Manu´a- lov´astr´anka fcntl(2) na Linuxu (2013) nedoporuˇcujemandatory locking pouˇz´ıvat, protoˇzeLinuxov´aimplementace obsahuje chyby kter´evedou k soubˇehu a mandatory zamyk´an´ınedok´aˇze tedy zajis- tit konzistenci. • Je d˚uleˇzit´esi uvˇedomit,ˇzepo skonˇcen´ıprocesu se vˇsechny z´amky, kter´edrˇzel uvoln´ı.

Zamyk´an´ısoubor˚u: struct flock

• l type . . . typ z´amku – F RDLCK . . . sd´ılen´yz´amek(pro ˇcten´ı),v´ıceproces˚u – F WRLCK . . . exkluzivn´ız´amek(pro z´apis),jeden proces – F UNLCK . . . odemˇcen´ı • l whence . . . jako u lseek(), tj. SEEK SET, SEEK CUR, SEEK END • l start . . . zaˇc´atekzamykan´eho´usekuvzhledem k l whence • l len . . . d´elka ´usekuv bajtech, 0 znamen´ado konce souboru • l pid . . . PID procesu drˇz´ıc´ıhoz´amek,pouˇz´ıv´ase jen pro F GETLK pˇrin´avratu

• soubory se daj´ızamykat po ˇc´astech a d´ase zjistit, kter´yproces drˇz´ız´amek. Pˇriukonˇcen´ıprocesu se automaticky uvoln´ıvˇsechny jeho z´amky.

• pokud pˇripouˇzit´ı F GETLK nen´ıpˇr´ısluˇsn´aˇc´astsouboru zamˇcen´a,je struk- tura flock vr´acenabez zmˇeny kromˇeprvn´ıpoloˇzky, kter´aje nastavena na F UNLCK. • pˇr´ıklad: file-locking/fcntl-locking.c

• pˇr´ıklad na fcntl (je to pomoc´ı fcntl ,,opraven´a”verze dˇr´ıvejˇs´ıho pˇr´ıkladu race/race.c ze strany 161): race/fcntl-fixed-race.c . • zamyk´an´ıpˇres fcntl i lockf m´ajednu d˚uleˇzitouvlastnost, kterou v´ystiˇznˇe popisuje napˇr´ıkladmanu´alov´astr´anka pro fcntl v syst´emu FreeBSD: This interface follows the completely stupid semantics of System V and IEEE Std 1003.1-1988 (“POSIX.1”) that require that all locks associated with a file for a given process are removed when any file descriptor for that file is closed by that process. This semantic means that applications must be aware of any

169 files that a subroutine library may access. For example if an application for updating the password file locks the password file database while making the update, and then calls getpwnam(3) to retrieve a record, the lock will be lost because getpwnam(3) opens, reads, and closes the password database. • Funkce lockf (souˇc´ast´ıSUSv3) je jednoduˇsˇs´ıvariantou fcntl, specifikuje se pouze jak zamknout a kolik bajt˚uod souˇcasn´epozice v souboru. Velmi ˇcasto je implementov´anajako wrapper kolem fcntl.

• Pˇr´ıklad file-locking/lockf.c demonstruje jak funguje mandatory loc- king a ukazuje pouˇzit´ıfunkce lockf.

Deadlock (aka uv´aznut´ı)

• m´amedva sd´ılen´ezdroje res1 a res2 chr´anˇen´ez´amky lck1 a lck2. Procesy p1 a p2 chtˇej´ıkaˇzd´yv´yluˇcn´ypˇr´ıstupk obˇema zdroj˚um. p1 p2 lock(lck1); /* OK */ lock(lck2); /* OK */ lock(lck2); /* Cek´anaˇ p2 */ lock(lck1); /* Cek´anaˇ p1 */ Deadlock use(res1, res2); use(res1, res2); unlock(lck2); unlock(lck2); unlock(lck1); unlock(lck1);

• pozor na poˇrad´ızamyk´an´ı!

• obecnˇedeadlock vznikne, jestliˇzeproces ˇcek´ana ud´alost,kter´anem˚uˇzena- stat. Zde napˇr.na sebe dva procesy ˇcekaj´ınavz´ajem,aˇzten druh´yuvoln´ı z´amek,ale k tomu nikdy nedojde. Dalˇs´ımoˇznost´ıje deadlock jednoho pro- cesu, kter´yˇctez roury a pˇredt´ımzapomnˇeluzavˇr´ıtz´apisov´ykonec roury. Jestliˇzerouru nem´auˇznikdo dalˇs´ıotevˇrenou,pokus o ˇcten´ıze zablokuje, protoˇzenejsou zavˇreny vˇsechny kopie z´apisov´ehodeskriptoru a tedy nena- stane konec souboru na rouˇre,ale ˇctouc´ı proces sv˚ujz´apisov´ydeskriptor nem˚uˇzezavˇr´ıt,protoˇzeˇcek´ave vol´an´ı read:

int main(void) { int c, fd; mkfifo("test", 0666); fd = open("test", O_RDWR);

170 read(fd, &c, sizeof(c)); /* never reached */ return (0); }

$ ./a.out ^C

• fcntl() prov´ad´ıkontrolu a pˇriv´yskytudeadlocku vr´at´ıchybu EDEADLK. • je vhodn´ese deadlocku snaˇzitvyvarovat spr´avn´ymnaprogramov´an´ıma ne- spol´ehatse na kontrolu syst´emu.

System V IPC

• IPC je zkratka pro Inter-Process Communication • komunikace mezi procesy v r´amcijednoho syst´emu, tj. nezahrnuje s´ıt’ovou komunikaci • semafory . . . pouˇzit´ıpro synchronizaci proces˚u • sd´ılen´apamˇet’ . . . pˇred´av´an´ıdat mezi procesy, pˇrin´aˇs´ı podobn´eprobl´emy jako sd´ılen´ısoubor˚u,k ˇreˇsen´ılze pouˇz´ıt semafory • fronty zpr´av . . . spojuj´ıkomunikaci (zpr´ava nese data) se synchronizac´ı(ˇcek´an´ıprocesu na pˇr´ıchod zpr´avy) • prostˇredkyIPC maj´ıpodobnˇejako soubory definovan´a pˇr´ıstupov´apr´ava (pro ˇcten´ıa z´apis)pro vlastn´ıka, skupinu a ostatn´ı.

• uvˇedomte si, ˇzetyto prostˇredkyse vztahuj´ıke konkr´etn´ımu syst´emu, Sys- tem V, kde se objevily jako prvn´ı. Dalˇs´ı syst´emy je pak pˇrevzaly. Ze tˇr´ı zde uveden´ych synchronizaˇcn´ıch prostˇredk˚uSystemu V se budeme zab´yvat pouze semafory. Pro sd´ılenoupamˇet’ je moˇzn´epouˇz´ıtjiˇz probran´evol´an´ı mmap, m´ıstozas´ıl´an´ızpr´avje moˇzn´epouˇz´ıtsockety (budou v nˇekter´ez pˇr´ıˇst´ıch pˇredn´aˇsek). • prostˇredkyIPC existuj´ıi pot´e,kdy skonˇc´ıproces, kter´yje vytvoˇril.O je- jich zruˇsen´ı je nutno explicitnˇepoˇz´adat(ze shellu lze zjistit seznam IPC prostˇredk˚upˇr´ıkazem ipcs a smazat je pˇr´ıkazem ipcrm). Stav a obsah exis- tuj´ıc´ıch prostˇredk˚uIPC z˚ust´av´av platnosti, i kdyˇzs nimi pr´avˇenepracuje ˇz´adn´yproces (napˇr.data ve sd´ılen´epamˇetiz˚ust´avaj´ı,i kdyˇzji nem´aˇz´adn´y proces pˇripojenou).

171 Semafory • zavedl je E. Dijkstra • semafor s je datov´astruktura obsahuj´ıc´ı – cel´enez´aporn´eˇc´ıslo i (voln´akapacita) – frontu proces˚u q, kter´eˇcekaj´ına uvolnˇen´ı • operace nad semaforem: init(s, n) vypr´azdnit s.q; s.i = n P(s) if(s.i > 0) s.i-- else uspat volaj´ıc´ıproces a zaˇraditdo s.q V(s) if(s.q pr´azdn´a)s.i++ else odstranit jeden proces z s.q a probudit ho

• P je z holandsk´eho,,proberen te verlagen” – zkus dekrementovat, V pak ze slova ,,verhogen” – inkrementovat.

• operace P(s) a V(s) lze zobecnit: hodnotu semaforu je moˇzn´emˇenito libo- volnou hodnotu n ... P(s, n), V(s, n). • Allen B. Downey: The Little Book of Semaphores, Second Edition, on-line na http://greenteapress.com/semaphores/ • bin´arn´ısemafor m´apouze hodnotu 0 nebo 1

172 Vz´ajemn´evylouˇcen´ıpomoc´ısemafor˚u

• jeden proces inicializuje semafor sem s; init(s, 1); • kritick´asekce se dopln´ıo operace nad semaforem ... P(s); kritick´asekce; V(s); ...

• inicializace semaforu na hodnotu n dovol´ıvstoupit do kritick´esekce n pro- ces˚um.Zde semafor funguje jako z´amek, vˇzdyho odemyk´a(zvyˇsujehodnotu) stejn´yproces, kter´yho zamknul (sn´ıˇzilhodnotu). • obecnˇeale m˚uˇzesemafor zvednout jin´yproces, neˇzkter´yho sn´ıˇzil;jinak by to ani nemˇelovelk´ysmysl. Je zde rozd´ıloproti z´amk˚um,viz strana 226.

173 API pro semafory

int semget(key t key, int nsems, int semflg ); • vr´at´ıidentifik´atorpole obsahuj´ıc´ıho nsems semafor˚uasociovan´y s kl´ıˇcem key (kl´ıˇc IPC PRIVATE . . . priv´atn´ısemafory, pˇri kaˇzd´empouˇzit´ıvr´at´ıjin´yidentifik´ator). semflg je OR-kombinace pˇr´ıstupov´ych pr´ava konstant IPC CREAT (vytvoˇrit,pokud neexistuje), IPC EXCL (chyba, pokud existuje). int semctl(int semid, int semnum, int cmd, ...); • ˇr´ıdic´ıfunkce, voliteln´yˇctvrt´yparametr arg je typu union semun. int semop(int semid, struct sembuf *sops, size t nsops ); • zobecnˇen´eoperace P a V.

• jak z´ıskat kl´ıˇcpro semget je vysvˇetlenona strane 177. • nejvˇetˇs´ızaj´ımavost na System V implementaci semafor˚uje skuteˇcnost,ˇze dan´ysyscall neoperuje nad jedn´ımsemaforem, ale nad polem semafor˚u, a to atomicky. Vˇetˇsinou vˇsakbudete potˇrebovat pouze jeden semafor, tj. pole o jednom prvku. Pro takov´epouˇzit´ıjsou System V semafory zbyteˇcnˇesloˇzit´e.

• pˇr´ıstupov´apr´ava jsou jen pro ˇcten´ıa z´apis;bit execute zde nem´asmysl. • podobn´esch´emaAPI funkc´ı(funkce na vytvoˇren´ı,ˇr´ızen´ıa operace) dodrˇzuj´ı i ostatn´ıSystem V IPC mechanismy. • jakmile je jednou pole semafor˚ujedn´ımprocesem vytvoˇreno,mohou i ostatn´ı procesy pouˇz´ıt semctl() a semop(), aniˇzby pˇredt´ımvolaly semget(). To plat´ıi pro semafory vytvoˇren´es kl´ıˇcem IPC PRIVATE, pro kter´enelze volat semget(), protoˇze by se t´ımvytvoˇrilonov´epole semafor˚u.Je to tak proto, aby i priv´atn´ısemafory mohly b´ytdˇedˇen´ev r´amci fork.

174 API pro semafory: semctl()

• semnum . . . ˇc´ıslosemaforu v poli • moˇzn´ehodnoty cmd: – GETVAL . . . vr´at´ıhodnotu semaforu – SETVAL ... nastav´ısemafor na hodnotu arg.val – GETPID . . . PID procesu, kter´yprovedl posledn´ıoperaci – GETNCNT . . . poˇcetproces˚uˇcekaj´ıc´ıch na vˇetˇs´ıhodnotu – GETZCNT . . . poˇcetproces˚uˇcekaj´ıc´ıch na nulu – GETALL . . . uloˇz´ıhodnoty vˇsech semafor˚udo pole arg.array – SETALL . . . nastav´ıvˇsechny semafory podle arg.array – IPC STAT . . . do arg.buf d´apoˇcetsemafor˚u, pˇr´ıstupov´a pr´ava a ˇcasyposledn´ıch semctl() a semop() – IPC SET . . . nastav´ıpˇr´ıstupov´apr´ava – IPC RMID . . . zruˇs´ıpole semafor˚u

• vol´an´ı semctl(semid, semnum, SETVAL, arg) odpov´ıd´aobecn´esemaforov´e inicializaˇcn´ıoperaci init(s, n).

175 API pro semafory: semop()

• operace se prov´ad´ıatomicky (tj. bud’ se povede pro vˇsechny semafory, nebo pro ˇz´adn´y)na nsops semaforech podle pole sops struktur struct sembuf, kter´aobsahuje: – sem num . . . ˇc´ıslosemaforu – sem op . . . operace ∗ P(sem num, abs(sem op)) pro sem op < 0 ∗ V(sem num, sem op) pro sem op > 0 ∗ ˇcek´an´ına nulovou hodnotu semaforu pro sem op == 0 – sem flg . . . OR-kombinace ∗ IPC NOWAIT . . . kdyˇznelze operaci hned prov´est,neˇcek´aa vr´at´ıchybu ∗ SEM UNDO . . . pˇriukonˇcen´ıprocesu vr´atitoperace se semaforem

• atomiˇcnostpˇresmnoˇzinu semafor˚uzajist´ı,ˇzenedojde k deadlocku v n´asleduj´ıc´ı situaci: dva procesy A a B budou pouˇz´ıvat dva semafory k ˇr´ızen´ıpˇr´ıstupu (zamyk´an´ı) ke dvˇemasyst´emov´ymzdroj˚um.Proces A je bude zamykat v poˇrad´ı(0, 1) a proces B v poˇrad´ı(1, 0). Ve chv´ıli,kdy proces A zamkne se- mafor 0 a B zamkne 1, dojde k deadlocku, protoˇzeani jeden proces nem˚uˇze pokraˇcovat (potˇreboval by zamknout druh´ysemafor). Pˇripouˇzit´ıatomick´e operace zamˇcen´ıobou semafor˚unajednou bude ´uspˇeˇsn´yvˇzdypr´avˇejeden proces, kter´yz´ısk´aoba semafory, druh´ybude ˇcekat.

• SEM UNDO zajist´ı,ˇzepˇriukonˇcen´ıprocesu dojde k odemˇcen´ısemafor˚u(pou- ˇzit´ych jako z´amky),kter´etento proces mˇelzamˇcen´e.

176 Vytv´aˇren´ıprostˇredk˚uIPC

• jeden proces prostˇredekvytvoˇr´ı,ostatn´ıse k nˇemu pˇripoj´ı. • po skonˇcen´ıpouˇz´ıv´an´ıje tˇrebaprostˇredekIPC zruˇsit.

• funkce semget(), shmget() a msgget() maj´ıjako prvn´ı parametr kl´ıˇcidentifikuj´ıc´ıprostˇredekIPC. Skupina proces˚u, kter´achce komunikovat, se mus´ıdomluvit na spoleˇcn´emkl´ıˇci. R˚uzn´eskupiny komunikuj´ıc´ıch proces˚uby mˇelym´ıtr˚uzn´ekl´ıˇce.

key t ftok(const char *path, int id ); • vr´at´ıkl´ıˇcodvozen´yze zadan´ehojm´enasouboru path a ˇc´ısla id. Pro stejn´e id a libovolnou cestu odkazuj´ıc´ına stejn´ysoubor vr´at´ıstejn´ykl´ıˇc. Pro r˚uzn´a id nebo r˚uzn´esoubory na stejn´em svazku vr´at´ır˚uzn´ekl´ıˇce.

pozn´amkyk ftok(): • z id se pouˇzijejen nejniˇzˇs´ıch 8 bit˚u. • nen´ıspecifikov´ano,zda bude stejn´ykl´ıˇcvr´aceni po smaz´an´ıa znovuvytvoˇren´ı souboru. Vˇetˇsinoune, protoˇzev kl´ıˇcise ˇcastoodr´aˇz´ıˇc´ıslo indexov´ehouzlu. • r˚uzn´ekl´ıˇcepro r˚uzn´esoubory nejsou vˇzdyzaruˇcen´e.Napˇr.na Linuxu se kl´ıˇcz´ısk´akombinac´ı16 bit˚uˇc´ıslai-uzlu, 8 bit˚u id a 8 bit˚uvedlejˇs´ıhoˇc´ısla zaˇr´ızen´ı.Stejn´ykl´ıˇcpro r˚uzn´esoubory je vr´acen,pokud se ˇc´ıslai-uzl˚ushoduj´ı na spodn´ıch 16 bitech. • pokud tedy nepˇr´ıbuzn´eprocesy chtˇej´ı pouˇz´ıvat stejn´ysemafor, mus´ı b´yt jm´ehosouboru pro kl´ıˇcdomluveno pˇredem. • pˇr´ıkladna semafory (je to pomoc´ısemafor˚u,,opraven´a”verze dˇr´ıvejˇs´ıhopˇr´ı- kladu race/race.c ze strany 161): race/sem-fixed-race.c .

177 Dalˇs´ıprostˇredkyIPC

• POSIX a SUSv3 definuj´ıjeˇstˇedalˇs´ıprostˇredkykomunikace mezi procesy: – sign´aly . . . pro uˇzivatelsk´e´uˇcely lze vyuˇz´ıtsign´aly SIGUSR1 a SIGUSR2 – POSIXov´asd´ılen´apamˇet’ pˇr´ıstupn´apomoc´ı shm open() a mmap() – POSIXov´esemafory ... sem open(), sem post(), sem wait(),... – POSIXov´efronty zpr´av ... mq open(), mq send(), mq receive(),... • Z BSD poch´az´ı sokety (sockets) umoˇzˇnuj´ıc´ıkomunikaci v dom´en´ach AF UNIX (komunikace v r´amcijednoho poˇc´ıtaˇce)a AF INET (komunikace na jednom poˇc´ıtaˇcinebo po s´ıti).

• POSIXov´eIPC pouˇz´ıv´apro pojmenov´an´ıjednotliv´ych IPC objekt˚uˇretˇezce m´ıstonumerick´ych identifik´ator˚u,proto do znaˇcn´em´ıryodpadaj´ıprobl´emy s identifikac´ızn´am´eze System V IPC (kde se ˇreˇs´ınapˇr.funkc´ı ftok()). • POSIXov´arozhran´ı zde uveden´ajsou souˇc´ast´ı rozˇs´ıˇren´ı 1003.1b (aka PO- SIX.4), viz strana6.

• sokety se z BSD rozˇs´ıˇrilyi do ostatn´ıch UNIXov´ych syst´em˚ua dostaly se i do normy SUSv2. • existuj´ıdalˇs´ıAPI specifick´epro konkr´etn´ısyst´em,napˇr.Solaris .

178 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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

S´ıt’ov´akomunikace

UUCP (UNIX-to-UNIX Copy Program) – prvn´ıaplikace pro komunikaci UNIXov´ych syst´em˚upropojen´ych pˇr´ımonebo pˇres modemy, souˇc´astVersion 7 UNIX (1978) sokety (sockets) – zavedeny ve 4.1aBSD (1982); soket je jeden konec obousmˇern´ehokomunikaˇcn´ıhokan´aluvytvoˇren´ehomezi dvˇemaprocesy bud’ lok´alnˇena jednom poˇc´ıtaˇci,nebo s vyuˇzit´ıms´ıt’ov´ehospojen´ı TLI (Transport Layer Interface) – SVR3 (1987); knihovna zajiˇst’uj´ıc´ıs´ıt’ovou komunikaci na ´urovni 4. vrstvy referenˇcn´ıho modelu ISO OSI RPC (Remote Procedure Call) – SunOS (1984); protokol pro pˇr´ıstupke sluˇzb´amna vzd´alen´emstroji, data pˇren´aˇsenave tvaru XDR (External Data Representation)

179 • ISO (International Standards Organization) OSI (Open Systems Intercon- nect) – vrstvy (layers): 1. fyzick´a(physical) 2. linkov´a(data link) 3. s´ıt’ov´a(network) 4. transportn´ı(transport) 5. relaˇcn´ı(session) 6. prezentaˇcn´ı(presentation) 7. aplikaˇcn´ı(application) • UUCP je tvoˇrenoaplikaˇcn´ımiprogramy, nevyˇzadujeˇz´adnoupodporu v j´adru. Implementace soket˚ua TLI jsou souˇc´ast´ıj´adra.TLI je ve verzi SVR4 imple- mentov´anos vyuˇzit´ımmechanismu STREAMS. RPC existuje jako knihovna linkovan´ak aplikac´ım,kter´avyuˇz´ıv´asokety (funguje nad protokoly TCP a UDP). RPC bylo vyvinuto jako komunikaˇcn´ıprotokol pro NFS (Networked File System). • existuje v´ıce(vz´ajemnˇenekompatibiln´ıch) implementac´ıRPC • komunikaˇcn´ıkan´alje specifikov´anadresami dvou soket˚u. • sokety pro komunikaci pouze v r´amcijednoho poˇc´ıtaˇcejsou v dom´enˇe AF UNIX a jejich jm´enajsou jm´enaspeci´aln´ıch soubor˚u,kter´ereprezentuj´ısokety v syst´emu soubor˚u. • sokety AF UNIX jsou nˇecojin´ehoneˇzlok´aln´ıTCP/IP komunikace pˇresloop- back rozhran´ı localhost (127.0.0.1). V´ıceo AF UNIX na stranˇe 186.

TCP/IP • protokoly – IP (Internet Protocol) – pˇr´ıstupn´yjen pro uˇzivatele root – TCP (Transmission Control Protocol) – streamov´y, spojovan´y,spolehliv´y – UDP (User Datagram Protocol) – datagramov´y, nespojovan´y,nespolehliv´y • IP adresa – 4 bajty (IPv4) / 16 bajt˚u(IPv6), definuje s´ıt’ov´e rozhran´ı,nikoliv poˇc´ıtaˇc • port – 2 bajty, rozliˇsen´ıv r´amci1 IP adresy, porty s ˇc´ıslem menˇs´ımneˇz1024 jsou rezervovan´e(jejich pouˇzit´ıvyˇzaduje pr´ava uˇzivatele root) • DNS (Domain Name System) – pˇrevod mezi symbolick´ymi jm´eny a numerick´ymiIP adresami

180 • pokud nev´ıte,o ˇcemje ˇreˇc,doporuˇcujiPeterkovy pˇredn´aˇsky;jsou volnˇeke staˇzen´ına webu. Jsou to nejlepˇs´ımateri´aly, kter´ejsem k dan´eproblematice vidˇel.

• UNIX pouˇz´ıv´apro s´ıt’ovou komunikaci nejˇcastˇejirodinu protokol˚uTCP/IP. Pro ´uˇcelyprogramov´an´ı aplikac´ı n´asbudou zaj´ımat pˇredevˇs´ım protokoly TCP (spojovan´aspolehliv´akomunikace) a UDP (nespojovan´anespolehliv´a komunikace). V obou protokolech je jeden konec komunikaˇcn´ıhokan´alu(od- pov´ıd´asoketu) identifikov´anIP adresou s´ıt’ov´ehorozhran´ıa ˇc´ıslemportu (po- moc´ıport˚use rozliˇsuj´ıs´ıt’ov´esluˇzby bˇeˇz´ıc´ına jednom poˇc´ıtaˇci).TCP spojen´ı je pak jednoznaˇcnˇedefinov´anojedn´ımp´aremsoket˚u. • IP – protokol 3. vrstvy, zajiˇst’uje pˇrenos paket˚u(datagram˚u)mezi rozhran´ımi identifikovan´ymiIP adresou; je nespolehliv´y(nezaruˇcujedoruˇcen´ıdat). Je definov´anv RFC 791. Ned´ılnou souˇc´ast´ıIP je Internet Control Message Pro- tocol (ICMP), RFC 792. • UDP – jednoduch´anadstavba nad IP, pˇrid´av´aˇc´ıslaport˚u,z˚ust´av´anespoleh- liv´ya datagramovˇeorientovan´y.RFC 768. • TCP – vytv´aˇr´ıobousmˇern´espojen´ımezi dvˇemabody (IP+port), poskytuje tok dat (stream) bez rozdˇelen´ına zpr´avy, zajiˇst’uje ˇr´ızen´ıtoku dat a spolehliv´e doruˇcov´an´ı.Pro vytvoˇren´ıspojen´ıje tˇreba prov´esttzv. handshake. RFC 793. • DNS – hierarchicky organizovan´adatab´aze,jej´ı struktura nemus´ı m´ıt nic spoleˇcn´ehose strukturou IP adres

Spojovan´esluˇzby (TCP), sekvenˇcn´ı obsluha

server ’ klients´ıt

fd = socket() fd = socket() bind(fd) listen(fd) fd2 = accept(fd) connect(fd) read(fd2); write(fd2) write(fd);read(fd) close(fd2) close(fd)

181 • uvˇedomte si, ˇzese pouˇz´ıvaj´ıbˇeˇzn´a read a write vol´an´ı. • server vytvoˇr´ıjedno spojen´ı,teprve po jeho ukonˇcen´ıakceptuje dalˇs´ıhokli- enta. • syst´emov´avol´an´ı:

– socket – vytvoˇr´ısoket, vr´at´ıjeho deskriptor – bind – definuje adresu soketu (IP adresu a ˇc´ısloportu), mus´ıto b´yt bud’ adresa jednoho ze s´ıt’ov´ych rozhran´ı poˇc´ıtaˇce,na kter´emje vy- tvoˇrensoket; pak bude soket pˇrij´ımatˇz´adostiklient˚upouze pˇrestoto rozhran´ı, nebo je to speci´aln´ı hodnota ,,libovoln´aadresa”; pak soket pˇrij´ım´apoˇzadavky prostˇrednictv´ımvˇsech s´ıt’ov´ych rozhran´ı(tzv. wild- card socket). – listen – ozn´am´ıj´adru,ˇzesoket bude pˇrij´ımatpoˇzadavky klient˚u – accept – usp´ıproces, dokud nebude k dispozici nˇejak´aˇz´adostklienta o spojen´ı, vytvoˇr´ı spojen´ı a vr´at´ı nov´ydeskriptor, pˇres kter´ybude prob´ıhat dalˇs´ı komunikace s klientem, p˚uvodn´ı deskriptor lze pouˇz´ıt k nov´emu vol´an´ı accept pro obslouˇzen´ıdalˇs´ıhoklienta – close – ukonˇc´ıkomunikaci – connect – ˇz´adostklienta o nav´az´an´ıspojen´ı,IP adresa a ˇc´ısloportu serveru se zad´avaj´ıjako parametry, komunikace prob´ıh´apˇresdeskriptor fd (na rozd´ılod accept nevytv´aˇr´ınov´ydeskriptor) • klient nemus´ıvolat bind, v takov´empˇr´ıpadˇemu j´adro pˇridˇel´ınˇekter´yvoln´y port. Existuj´ı sluˇzby (napˇr. rsh), kter´evyˇzaduj´ı, aby se klient spojoval z privilegovan´eho portu (porty 0-1023). Takov´yklient pak mus´ıprov´est bind (a nav´ıcbˇeˇzets dostateˇcn´ymipr´avyalespoˇndo okamˇzikuproveden´ı bind; do- stateˇcn´apr´ava mohou znamenat uˇzivatele root nebo speci´aln´ıprivilegium/capability).

182 Spojovan´esluˇzby (TCP), paraleln´ı obsluha server ’ klients´ıt

fd = socket() fd = socket() bind(fd) listen(fd) fd2 = accept(fd) connect(fd) fork() close(fd2) syn while(waitpid( read(fd2) write(fd);read(fd) -1, stat, write(fd2) WNOHANG)>0) ; exit(0) close(fd)

• server akceptuje spojen´ı od klienta a na vlastn´ı komunikaci vytvoˇr´ı nov´y proces, kter´ypo uzavˇren´ıspojen´ıs klientem skonˇc´ı.Rodiˇcovsk´yproces m˚uˇze mezit´ımakceptovat dalˇs´ıklienty a spouˇstˇetpro nˇeobsluˇzn´eprocesy. Souˇcasnˇe je tedy obsluhov´anov´ıceklient˚u.

• po proveden´ı fork, ale pˇredzah´ajen´ımobsluhy spojen´ı,m˚uˇzesynovsk´yproces prov´est exec – takto funguje napˇr. inetd (strana 208). • vol´an´ı waitpid v cyklu odstraˇnujeze syst´emu zombie. Jinou moˇznost´ı je vyuˇzit´ısign´alu SIGCHLD, jehoˇzexplicitn´ıignorov´an´ızabr´an´ıvzniku ˇziv´ych mrtv´ych, popˇr.lze instalovat handler, v nˇemˇzse vol´a wait.

183 Spojovan´esluˇzby, paraleln´ı accept()

server s´ıt’ klient

fd = socket() fd = socket() bind(fd) listen(fd) fork() ... fd2=accept(fd) connect(fd) read(fd2) write(fd);read(fd) write(fd2) close(fd2) close(fd)

• po bind a listen se vytvoˇr´ınˇekolik synovsk´ych proces˚ua kaˇzd´yv cyklu vol´a accept a obsluhuje klienty. J´adro,pro uˇzivatele nedeterministicky, vybere pro kaˇzd´ypoˇzadavek jeden proces, v nˇemˇz accept nav´aˇzespojen´ı.Hlavn´ı proces ˇz´adn´epoˇzadavky nevyˇrizuje,ale ˇcek´av nˇekter´emz vol´an´ıtypu wait a vytv´aˇr´ıprocesy, kdyˇzje potˇreba.

• jednotliv´eprocesy serveru mezi sebou mohou komunikovat, aby v pˇr´ıpadˇe, ˇzesouˇcasn´ych poˇzadavk˚uje v´ıceneˇzserverov´ych proces˚u,se tato skuteˇcnost zjistila a hlavn´ıserver mohl dynamicky vytvoˇritdalˇs´ıserverov´yproces. • takto funguje napˇr.webov´yserver Apache. Je moˇzn´edefinovat, kolik poˇza- davk˚um´apotomek zpracovat, neˇzs´amskonˇc´ı.T´ımto zp˚usobem se v´yraznˇe omez´ın´asledkypˇr´ıpadn´ych probl´em˚u,napˇr´ıkladneuvolˇnov´an´ıpamˇeti,tzv. memory leaks. • vˇsechny tˇriuveden´ezp˚usoby ˇcinnostiserveru funguj´ıse stejn´ym klientem – ˇcinnostklienta nez´avis´ına variantˇeserveru.

184 Datagramov´esluˇzby (UDP)

server ’ klients´ıt

fd = socket() fd = socket() bind(fd)

recvfrom(fd) sendto(fd) sendto(fd) recvfrom(fd)

close(fd)

• z pohledu volan´ych s´ıt’ov´ych funkc´ıje funkce serveru a klienta shodn´a.Klient je zde ten, kdo poˇsleprvn´ıdatagram.

• stejnˇejako v pˇr´ıpadˇeTCP, klient nemus´ı dˇelat bind, jestliˇzemu nez´aleˇz´ı na tom, jak´eˇc´ısloportu bude pouˇz´ıvat. Server zjist´ıport klienta z obsahu adresn´ıˇc´astidatagramu.

• v´yhodou nespojovan´esluˇzby je menˇs´ıreˇziea to, ˇzepˇresjeden soket lze komu- nikovat s v´ıce procesy (pˇrispojovan´ekomunikaci je spojen´ıvˇzdynav´az´anos jedn´ımprocesem).

• pro UDP je moˇzn´evolat connect. T´ım se nenav´aˇzespojen´ı, ale soket se nastav´ıtak, ˇzem˚uˇzenad´alekomunikovat pouze s adresou a portem speci- fikovan´ymive vol´an´ı connect. M´ısto sendto a recvfrom se pak pouˇz´ıvaj´ı funkce send a recv.

185 Vytvoˇren´ısoketu: socket()

int socket(int domain, int type, int protocol ); • vytvoˇr´ısoket a vr´at´ıjeho deskriptor. • domain – ,,kde se bude komunikovat”: – AF UNIX . . . lok´aln´ıkomunikace, adresa je jm´enosouboru – AF INET, AF INET6 . . . s´ıt’ov´akomunikace, adresa je dvojice (IP adresa, port) • type: – SOCK STREAM . . . spojovan´aspolehliv´asluˇzba,poskytuje obousmˇern´ysekvenˇcn´ıproud dat – SOCK DGRAM . . . nespojovan´anespolehliv´asluˇzba,pˇrenos datagram˚u • protocol: 0 (default pro dan´y type) nebo platn´eˇc´ıslo protokolu (napˇr. 6 = TCP, 17 = UDP)

• funkce je deklarov´anav , stejnˇejako funkce z dalˇs´ıch slajd˚u – bind, listen, a accept, a pouˇzit´ekonstanty. • sokety jsou pˇr´ıstupn´epˇresdeskriptory soubor˚u. Po nav´az´an´ıspojen´ı je (spojovan´a)komunikace pˇressoket podobn´akomunikaci pomoc´ıroury s t´ımrozd´ılem,ˇzesokety jsou vˇzdy obousmˇern´e, coˇznemus´ıplatit u rour, viz strana 137.

• ˇcastouvid´ıte konstanty zaˇc´ınaj´ıc´ı PF_ (jako protocol family, napˇr. PF IN- ET, PF_UNIX, nebo PF INET6) a pouˇz´ıvan´eve vol´an´ı socket. Konstanty AF_ (address family) jsou pak pouˇz´ıvan´epouze pˇrizad´av´an´ıadres soket˚u.I kdyˇz to snad d´av´avˇetˇs´ısmysl, norma specifikuje pouze AF konstanty pro pouˇzit´ı pro vol´an´ı socket i pro zad´av´an´ıadres. Hodnoty odpov´ıdaj´ıc´ıch konstant PF jsou pak stejn´e,tj. definovan´epomoc´ı AF konstant. Doporuˇcujipouˇz´ıvat jen AF. • existuj´ıdalˇs´ıtypy soket˚upro pln´ypˇr´ıstupk dan´emu protokolu (SOCK RAW), nebo k informac´ımz routovac´ıtabulky. Pro pouˇzit´ı SOCK RAW typicky potˇrebujete dodateˇcn´aprivilegia – proto napˇr´ıkladpˇr´ıkaz ping, kter´yvyplˇnuje ICMP hlaviˇckyodes´ılan´ych paket˚u,b´yv´anastaven jako SUID:

$ ls -l /usr/sbin/ping -r-sr-xr-x 1 root bin 55680 Nov 14 19:01 /usr/sbin/ping

186 Pojmenov´an´ısoketu: bind()

int bind(int socket, const struct sockaddr *address, socklen t address len ); • pˇriˇrad´ısoketu zadan´emu deskriptorem socket adresu • obecn´a struct sockaddr, nepouˇz´ıv´ase pro vlastn´ızad´av´an´ı adres: – sa family t sa family . . . dom´ena – char sa data [] . . . adresa • pro AF INET se pouˇz´ıv´a struct sockaddr in: – sa family t sin family . . . dom´ena(AF INET) – in port t sin port . . . ˇc´ısloportu (16 bit˚u) – struct in addr sin addr . . . IP adresa (32 bit˚u) – unsigned char sin zero [8] . . . v´yplˇn(padding)

• vol´an´ı bind pˇriˇrazujesoketu lok´aln´ıadresu, tj. zdrojovou adresu odes´ılan´ych dat a c´ılovou adresu pˇrij´ıman´ych dat. Vzd´alen´aadresa, tj. adresa druh´eho konce komunikaˇcn´ıhokan´alu,se nastavuje pomoc´ı connect. • struktura sockaddr je obecn´ytyp, pouˇz´ıvan´ykernelem. Pro konkr´etn´ına- staven´ı adres pak podle zvolen´edom´eny a typu lze pouˇz´ıt ,,konkr´etnˇejˇs´ı” struktury k tomu definovan´e(viz dalˇs´ıslajd), kter´eje pak nutn´epˇri pouˇzit´ı v bind pˇretypovat na struct sockaddr. V naprost´evˇetˇsinˇepˇr´ıpad˚uje ale pouˇzit´ıtˇechto struktur zbyteˇcn´ea nedoporuˇcen´e- program pak bude fungo- vat pouze pro jednu address family. Pˇripouˇzit´ıobecn´ych funkc´ıpro pˇrevod jmen na adresy se lze pouˇzit´ı tˇechto struktur ´uplnˇevyhnout - viz funkce getaddrinfo na stranˇe 199. • Budete potˇrebovat i dalˇs´ıhlaviˇckov´esoubory. Pˇr´ıkladje na stranˇe 188.

• pro dom´eny AF INET a AF INET6 lze zadat ˇc´ısloportu a speci´aln´ıhodnotu IP adresy, kter´aznamen´alibovolnou adresu na dan´emstroji. Na takov´ysoket (wildcard soket) pak bude moˇzn´epˇr´ıj´ımatpoˇzadavky na kteroukoli IP adresu nastavenou na kter´ekoli s´ıt’ov´ekartˇe.Je moˇzn´ezadat i jednu konkr´etn´ıadresu, k tomu se dostaneme.

– pro AF INET je to hodnota INADDR ANY (4 nulov´ebajty odpov´ıdaj´ıc´ı adrese 0.0.0.0) – u AF INET6 je situace komplikovanˇejˇs´ı,bud’to lze pouˇz´ıtkonstantn´ıpro- mˇennou in6addr any nebo konstantu IN6ADDR ANY INIT, kterou ale lze

187 pouˇz´ıtpouze pro inicializaci promˇenn´e(typu struct in6 addr), niko- liv pro pˇriˇrazen´ı.Obˇetyto hodnoty odpov´ıdaj´ıadrese :: (16 nulov´ych bajt˚u).

• nelze spojit v´ıcesoket˚us jednou dvojic´ı(adresa, port).

• vol´an´ı bind lze vynechat, j´adropak soketu (v pˇr´ıpadˇeTCP, UDP) pˇriˇrad´ı adresu a nˇekter´yvoln´yport. Obvykle bind vol´apouze server, protoˇzeklienti oˇcek´avaj´ı,ˇzebude poslouchat na pevn´emportu. Naopak klient pevn´yport nepotˇrebuje,server se port klienta dozv´ıpˇrinav´az´an´ıspojen´ınebo z prvn´ıho pˇrijat´ehodatagramu. • adresa i port mus´ıb´ytdo struktury uloˇzeny vˇzdyv s´ıt’ov´empoˇrad´ı bajt˚u. Poˇrad´ıbajt˚ubylo vysvˇetlenona stranˇe 18, dalˇs´ıinformace pak jsou na stranˇe 198.

Struktura pro IPv4 adresy • kaˇzd´aadresn´ırodina m´asvoji strukturu a sv˚ujhlaviˇckov´y soubor • pouˇzitoustrukturu pak ve vol´an´ı socket pˇretypujete na struct sockaddr

#include struct sockaddr_in in; /* IPv4 */

bzero(&in, sizeof (in)); in.sin_family = AF_INET; in.sin_port = htons(2222); in.sin_addr.s_addr = htonl(INADDR_ANY);

if (bind(s, (struct sockaddr *)&in, sizeof (in)) == -1) ...

• Tento pˇr´ıklad slouˇz´ıˇcistˇepro demonstraci toho jak funguj´ı struktury uv- nitˇr.Pokud to nen´ınezbytnˇenutn´e,nemˇelby k´odkter´ynap´ıˇsetetyto kon- strukce obsahovat - pˇripouˇzit´ıobecn´ych funkc´ıpro pˇrevod jm´enana adresy vyplˇnov´an´ıstruktur specifick´ych pro danou address family odpad´a.U vˇetˇsiny s´ıt’ov´ych program˚use dnes pˇredpokl´ad´a,ˇzebudou fungovat jak na IPv4, tak na IPv6.

• u IPv4 je poloˇzka sin addr sama strukturou, typu in addr. Tato struktura mus´ım´ıtalespoˇnjednu poloˇzku, s addr, jej´ıˇztyp mus´ıb´ytekvivaletn´ı4- bajtov´emu integeru – pro ˇctyˇribajty IPv4 adresy. To ˇr´ık´apˇr´ımoUNIX norma pro soubor netinet/in.h.

188 • sockaddr in6 je o nˇecosloˇzitˇejˇs´ı.Je pˇr´ıstupn´yz netinet/in.h (bud’to je v nˇemtato struktura pˇr´ımodefinov´ananebo soubor inkluduje netinet6/in6.h s jej´ıdefinic´ı).

• u AF INET a AF INET6 mus´ıb´ytport i adresa v s´ıt’ov´empoˇrad´ıbajt˚u,viz strana 198.

• INADDR ANY je definovan´ajako 0, takˇzeˇcastouvid´ıtejej´ıpouˇzit´ıbez htonl. Nen´ıto dobr´yzvyk. Aˇzm´ıstotohoto makra vloˇz´ıteIP adresu definovanou integerem a zapomenete htonl pˇridat,je hned probl´em.Kdyˇzbudete od zaˇc´atkuprogramovat jako sluˇsnˇevychovan´ılid´e,toto se v´amnem˚uˇzest´at.A kdyˇzbudete ps´ats´ıt’ov´eprogramy tak aby uˇzod zaˇc´atkubyly agnostick´ek address family, tak se tomuto probl´emu vyhnete ´uplnˇe.

• v dom´enˇe AF UNIX se pouˇz´ıv´aadresov´astruktura struct sockaddr un, de- finovan´av : – sa family t sun family . . . dom´ena – char sun path [] . . . jm´enosoketu – d´elka jm´enanen´ıve standardu definov´ana,z´avis´ına implementaci. Ob- vykl´ehodnoty jsou mezi 92 a 108.

Cek´an´ınaˇ spojen´ı: listen()

int listen(int socket, int backlog ); • oznaˇc´ısoket zadan´ydesktriptorem socket jako akceptuj´ıc´ı spojen´ıa syst´emna soketu zaˇcneposlouchat.

• maxim´alnˇe backlog ˇz´adost´ıo spojen´ım˚uˇzenajednou ˇcekat ve frontˇena obslouˇzen´ı(implementace m˚uˇzehodnotu backlog zmˇenit,pokud nen´ıv podporovan´emrozsahu). Z´adosti,kter´eseˇ nevejdou do fronty, jsou odm´ıtnuty (tj. vol´an´ı connect skonˇc´ıs chybou). • soket ˇcek´ana spojen´ına adrese, kter´amu byla dˇr´ıve pˇriˇrazena vol´an´ım bind.

• Wildcard sokety se pouˇz´ıv´aj´ıpro server nejˇcastˇeji.Konkr´etn´ıIP adresa ser- veru se zad´av´atehdy, jestliˇzeje potˇrebarozliˇsit,pˇreskter´es´ıt’ov´erozhran´ı pˇriˇselpoˇzadavek na spojen´ı(pro kaˇzd´erozhran´ım´amejeden soket). Tuto moˇznostvyuˇz´ıvaly web servery, kter´epodle IP adresy rozliˇsovaly virtu´aln´ı

189 servery. Obvykle se na takov´emserveru jednomu fyzick´emu rozhran´ıpˇriˇradilo nˇekolik IP adres (IP aliasing). To je ale jiˇzd´avnominulost´ı– rozliˇsen´ıvir- tu´aln´ıch server˚upodle HTTP hlaviˇcky,,Host:” uˇznepotˇrebujeIP aliasy. PodobnˇeTLS protokol obsahuje rozˇs´ıˇren´ı ServerName. • To ˇzesyst´emzaˇcnena portu poslouchat znamen´a,ˇzepo pˇripojen´ıprobˇehne TCP handshake a syst´emzaˇcnepˇrij´ımatdata. Data se ukl´adaj´ıdo bufferu s omezenou velikost´ı,a po dosaˇzen´ıjeho limitu je spojen´ısice st´aleaktivn´ı,ale TCP window je nastaveno na 0 – syst´emdalˇs´ıdata pˇrestalpˇrij´ımat.Velikost bufferu b´yv´av ˇr´adudes´ıtekkilobajt˚u.Pˇr´ıklad: tcp/up-to-listen-only.c .

• V pˇr´ıkladu je pouˇzitomakro SOMAXCONN, vyˇzadovan´enormou v souboru sys/socket.h. Specifikuje maxim´aln´ıpovolenou d´elkufronty pro listen(). Co se d´ıv´amna r˚uzn´everze syst´em˚uco m´amk dispozici, tak Linux, FreeBSD, Mac OS X i Solaris pouˇz´ıvaj´ıpro toto makro hodnotu 128.

Akceptov´an´ıspojen´ı: accept()

int accept(int socket, struct sockaddr *address, socklen t *address len ); • vytvoˇr´ıspojen´ımezi lok´aln´ımsoketem socket (kter´ydˇr´ıve zavolal listen) a vzd´alen´ymsoketem, ˇz´adaj´ıc´ımo spojen´ı pomoc´ı connect. Vr´at´ıdeskriptor (nov´ysoket), kter´ylze pouˇz´ıvat pro komunikaci se vzd´alen´ymprocesem. P˚uvodn´ı soket m˚uˇzehned pˇrij´ımatdalˇs´ıspojen´ıpomoc´ı accept. • v address vr´at´ıadresu vzd´alen´ehosoketu. • address len je velikost struktury pro uloˇzen´ıadresy v bajtech, po n´avratuobsahuje skuteˇcnoud´elkuadresy.

• Vytvoˇren´ıdruh´ehodeskriptoru pro komunikaci umoˇzˇnujena tom p˚uvodn´ım ihned znovu volat accept. • Novˇevytvoˇren´ysoket m´astejn´evlastnosti, jako m´asoket socket, tj. pokud je napˇr´ıkladneblokuj´ıc´ı,je i nov´ysoket neblokuj´ıc´ı. • Jestliˇzese v´ıceklient˚uze stejn´ehopoˇc´ıtaˇcenajednou pˇripoj´ık jednomu ser- veru (tj. na jednu serverovou IP adresu a jeden port), jsou jednotliv´aspojen´ı rozliˇsenajen ˇc´ıslemportu na klientsk´estranˇe.Nezapomeˇnte,ˇzeTCP spojen´ı je jednoznaˇcnˇedefinov´anodvˇemasokety, tj. ((addr1, port1), (addr2, port2)).

190 • address m˚uˇzeb´ytzad´anajako NULL, ˇc´ımˇzoznamujeme, ˇzen´askonkr´etn´ı adresa naˇsehonov´ehosoketu nezaj´ım´a.V tomto pˇr´ıpadˇeby i address len mˇelob´yt 0. • Pokud je program naps´anspr´avnˇea je tedy nez´avisl´yna address family, mˇel by v druh´emargumentu pˇred´avat adresu struktury struct sockaddr storage (do kter´ese vejde jak´akoliv struktura specifick´apro danou address family, tedy struct sockaddr in nebo struct sockaddr in6) a v tˇret´ım argu- mentu jej´ıd´elku.

• Pˇr´ıklad: tcp/tcp-sink-server.c

Pr´aces IPv4 a IPv6 adresami • bin´arn´ıreprezentace adresy se n´am ˇspatnˇeˇcte • a reprezentaci adresy ˇretˇezcemnelze pouˇz´ıtpˇripr´acise sockaddr strukturami int inet pton(int af, const char *src, void *dst ); • pˇrevede ˇretˇezecna bin´arn´ıadresu, tj. to co je moˇzn´epouˇz´ıtv in addr nebo in6 addr poloˇzk´ach sockaddr struktur • vrac´ı1 (OK), 0 (chybnˇezadan´aadresa) nebo -1 (a nastav´ı errno) cont char *inet ntop(int af, const void *src, char *dst, size t size ); • opak k inet pton; vrac´ı dst nebo NULL (a nastav´ı errno) • pro obˇevol´an´ıplat´ı,ˇze af je AF INET nebo AF INET6

• Funkce jsou deklarovan´ev arpa/inet.h. • inet pton vrac´ı1 pokud konverze probˇehla,0 pokud dan´yˇretˇezecnen´ıad- resa dan´eadresn´ırodiny, a -1 pokud af nen´ıpodporov´ano(EAFNOSUPPORT). inet ntop vrac´ı dst pokud je vˇseOK a NULL s nastaven´ym errno pokud ne. • Adresy i porty v bin´arn´ıpodobˇejsou v s´ıt’ov´empoˇrad´ıbajt˚u,jak lze oˇcek´avat. • dst mus´ıb´ytdostateˇcnˇevelk´e,protoˇzezde nen´ıparametr specifikuj´ıc´ıve- likost. To ale nen´ıprobl´em,podle nastaven´ı af pouˇzijetekonkr´etn´ıadresn´ı strukturu nebo ˇretˇezec.Pro maxim´aln´ıpostaˇcuj´ıc´ıvelikost ˇretˇezc˚upro adresy norma definuje dvˇemakra, INET ADDRSTRLEN (16) a INET6 ADDRSTRLEN (48). Je to vˇcetnˇem´ıstapro ukonˇcuj´ıc´ı \0. • size je velikost ˇretˇezce dst. Pokud nen´ıdostateˇcn´a,vol´an´ıselˇzes chybou ENOSPC.

191 • n je network, p je presentable • Pro IPv4 adresy se pouˇz´ıvala vol´an´ı inet aton a inet ntoa (a jako ascii). D´ıky nov´ymvol´an´ım jiˇztyto funkce nen´ı potˇrebapouˇz´ıvat. Vˇsechna tato vol´an´ıb´yvaj´ızdokumentov´anav manu´alov´estr´ance inet. • Uvˇedomte si, ˇzepomoc´ıtˇechto funkc´ım˚uˇzetepˇrev´estnajednou jen jeden typ, to je bud’ IPv4, anebo IPv6 adresu. Kdyˇznev´ıte,co ˇcekat, zkus´ıtejednu a pokud to nevyjde, zkus´ıtedruhou. Pˇr´ıklad: resolving/addresses.c .

Nav´az´an´ıspojen´ı: connect()

int connect(int sock, struct sockaddr *address, socklen t address len); • nav´aˇzespojen´ılok´aln´ıhosoketu sock se vzd´alen´ymprocesem, kter´ypomoc´ı listen a accept ˇcek´ana spojen´ına adrese address (o d´elce address len). • jestliˇzepro soket sock nebyla definov´anaadresa vol´an´ım bind, je mu pˇriˇrazenanˇejak´anepouˇzit´aadresa dle zvolen´erodiny protokol˚u. • pokud se spojen´ınepovede, je soket v nedefinovan´emstavu. Pˇrednov´ympokusem o spojen´ıby aplikace mˇelazavˇr´ıt deskriptor sock a vytvoˇrit nov´ysoket.

• Po ´uspˇeˇsn´emnav´az´an´ıspojen´ımohou server i klient pro komunikaci pouˇz´ıvat bˇeˇzn´asouborov´avol´an´ı write a read, nebo funkce send, recv, sendmsg, recvmsg. Chov´an´ıfunkc´ıpro z´apisa ˇcten´ıdat je podobn´ejako write a read pro roury.

• Pˇr´ıklad: tcp/connect.c

• I pro nespojovan´esluˇzby (UDP) se d´avolat connect, t´ımse nenav´aˇzespo- jen´ı,ale pouze se omez´ıadresa protistrany, se kterou je moˇzn´epˇressoket komunikovat. Pro pos´ıl´an´ıdatagram˚use pak pouˇz´ıvaj´ıfunkce send a recv, kter´euˇznemaj´ı parametr pro adresu protistrany. Pro nespojovan´esluˇzby m˚uˇzemetak´evolat connect() v´ıcekr´at,kaˇzd´evol´an´ınovˇenastav´ıadresu ko- munikuj´ıc´ıstrany. Pokud pouˇzijemem´ıstoadresy NULL, nastaven´ıprotistrany je zresetov´ano. • Pokud je socket nastaven jako neblokuj´ıc´ı,viz strana 104, connect se ne- zablokuje ˇcek´an´ım na spojen´ı. M´ısto toho vr´at´ı -1 s errno nastaven´ena

192 EINPROGRESS (= “nebylo moˇzn´evytvoˇritspojen´ıokamˇzitˇe”),a ˇz´adosto spo- jen´ıse uloˇz´ıdo syst´emov´efronty pro n´asledn´evyˇr´ızen´ı.Do t´edoby, neˇzje spojen´ıpˇripraveno, vol´an´ı connect vrac´ı -1, nyn´ıale s chybou EALREADY. Nen´ıale takto vhodn´etestovat pˇripravenost spojen´ı,protoˇzepokud connect skonˇc´ıs chybou, dalˇs´ıvol´an´ı connect provede nov´ypokus o spojen´ıa jsme opˇettam, kde jsme byli. . . Je moˇzn´eale pouˇz´ıt select nebo poll pro ˇcek´an´ı na z´apis(ne ˇcten´ı) do socketu, viz strany 204, 207 kter´eobsahuj´ıkompletn´ı pˇr´ıkladna neblokuj´ıc´ıconnect, viz strana 205.

Pˇrijet´ızpr´avy: recvfrom()

ssize t recvfrom(int sock, void *buf, size t len, int flg, struct sockaddr *address, socklen t *address len ); • pˇrijmezpr´avuze soketu sock, uloˇz´ıji do bufferu buf o velikosti len, do address d´aadresu odes´ılatelezpr´avy, do address len d´elkuadresy. Vr´at´ıd´elkuzpr´avy. Kdyˇzje zpr´ava delˇs´ıneˇz len, nadbyteˇcn´adata se zahod´ı(SOCK STREAM nedˇel´ıdata na zpr´avy, data se nezahazuj´ı). • ve flg mohou b´ytpˇr´ıznaky: – MSG PEEK . . . zpr´ava se bere jako nepˇreˇcten´a,dalˇs´ı recvfrom ji vr´at´ıznovu – MSG OOB . . . pˇreˇcteurgentn´ı(out-of-band) data – MSG WAITALL . . . ˇcek´a,dokud nen´ınaˇctenpln´yobjem dat, tj. len bajt˚u

• pouˇz´ıv´ase hlavnˇepro sokety typu SOCK DGRAM. V takov´esituaci opˇetˇcek´a na celou zpr´avu,tj. nevr´at´ıv´amp˚ulkudatagramu. Opˇetje moˇzn´enastavit socket jako neblokuj´ıc´ı. • address len mus´ı b´ytinicializovan´avelikost´ı bufferu, pokud nen´ı adresa NULL, ˇc´ımˇzˇr´ık´ate,ˇzev´asadresa protistrany nezaj´ım´a– tomu tak ale u da- tagram˚uvetˇsinou nen´ı. • m´ısto recvfrom se d´apouˇz´ıtobecnˇejˇs´ıfunkce recvmsg. • pro sokety, na kter´ebylo vol´ano connect, se m´ısto funkce recvfrom vol´a recv. • po ´uspeˇsn´emn´avratuz recvfrom je moˇzn´e address a address len beze zmˇeny pouˇz´ıtpro n´asledn´evol´an´ı sendto. • stejnˇejako sendto, je i recvfrom moˇzn´epouˇz´ıtpro spojovanou sluˇzbu.Z´ıskat adresu protistrany je ale asi jednoduˇsˇs´ıpˇresvol´an´ı getpeername, viz strana 195.

193 • pˇr´ıklad: udp/udp-server.c

Posl´an´ızpr´avy: sendto()

ssize t sendto(int socket, void *msg, size t len, int flags, struct sockaddr *addr, socklen t addr len ); • prostˇrednictv´ımsoketu socket poˇslezpr´avu msg o d´elce len na adresu addr (o d´elce addr len). • parametr flags m˚uˇzeobsahovat pˇr´ıznaky: – MSG EOB . . . ukonˇcen´ız´aznamu (pokud je podporov´ano protokolem) – MSG OOB . . . posl´an´ıurgentn´ıch (out-of-band) dat, jejichˇz v´yznamje z´avisl´yna protokolu

• Pouˇz´ıv´ase hlavnˇepro sokety typu SOCK DGRAM, protoˇzev t´etosituaci m´ame pouze socket reprezentuj´ıc´ı naˇsistranu spojen´ı; viz pozn´amka u slajdu k accept. Mus´ımeproto specifikovat adresu protistrany, coˇzvol´an´ım write ne- dok´aˇzeme.Pro datagramovou sluˇzbuse nav´ıcdata berou jako nedˇeliteln´a, tj. bud’ se akceptuj´ıcel´a,nebo se vol´an´ızablokuje – neexistuje ˇc´asteˇcn´yz´apis. Stejnˇejako je tomu u souborov´ych deskriptor˚u,je i zde moˇzn´esocket nastavit jako neblokuj´ıc´ı,viz strana 104.

• M´ısto sendto se d´apouˇz´ıtobecnˇejˇs´ıfunkce sendmsg. • Pro sokety, na kter´ebylo vol´ano connect, se m´ısto sendto m˚uˇzepouˇz´ıt send. • Uspˇeˇsn´yn´avratz´ libovoln´efunkce zapisuj´ıc´ı data do soketu neznamen´a ´uspˇeˇsn´edoruˇcen´ızpr´avyprotistranˇe, ale pouze uloˇzen´ıdat do lok´aln´ıho bufferu odes´ılan´ych dat.

• Pokud pouˇzijete sendto na streamovanou sluˇzbu, je to moˇzn´e,ale adresa se ignoruje. Jedin´yd˚uvod proˇcnepouˇz´ıtpˇr´ımo write by tak byla moˇznost pouˇz´ıtflagy. V tom pˇr´ıpadˇeje ale jednoduˇsˇs´ıpouˇz´ıt send.

• Pˇr´ıklad: udp/udp-client.c .

194 Dalˇs´ıfunkce pro sokety

int setsockopt(int socket, int level, int opt name, const void *opt value, socklen t option len ); • nastaven´ıparametr˚usoketu int getsockopt(int socket, int level, int opt name, void *opt value, socklen t *option len ); • pˇreˇcten´ıparametr˚usoketu int getsockname(int socket, struct sockaddr *address, socklen t *address len ); • zjiˇstˇen´ı(lok´aln´ı)adresy soketu int getpeername(int socket, struct sockaddr *address, socklen t *address len ); • zjiˇstˇen´ıadresy vzd´alen´ehosoketu (druh´ehokonce spojen´ı)

• hodnota level v getsockopt a setsockopt je obvykle SOL_SOCKET.U get- sockopt, option len mus´ı b´ytinicializov´anana velikost opt value. • funkce getsockname se pouˇz´ıv´a,kdyˇznevol´ame bind a potˇrebujemezjistit, jak´a(lok´aln´ı!)adresa byla j´adremsoketu pˇridˇelena.

• vol´an´ı getsockopt(sock, SOL_SOCKET, SO_ERROR, &val, &len) vr´at´ı (a vymaˇze)pˇr´ıznak chyby na soketu. Asi nejuˇziteˇcnˇejˇs´ı je pˇrizjiˇst’ov´an´ı, jak dopadl neblokuj´ıc´ı connect, viz strana 192. • pˇripouˇzit´ı SO_REUSEADDR se d´apo uzavˇren´ıposlouchaj´ıc´ıhoserverov´ehoso- ketu znovu spustit server – volat socket, bind, listen a accept na stejn´e adrese a portu – i kdyˇzjeˇstˇedob´ıhaj´ıspojen´ıvytvoˇren´apˇredchoz´ıinstanc´ı serveru:

int opt = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

• Pouˇzit´ı setsockopt s SO_REUSEADDR je vidˇetnapˇr.v pˇr´ıkladu tcp/reuseaddr.c . Pozor na to, ˇzemus´ıteudˇelatalespoˇnjedno spojen´ı,jinak syst´emnem´ana co ˇcekat a opakovan´y bind za sebou se podaˇr´ıi tak.

195 Uzavˇren´ısoketu: close()

int close(int fildes); • zruˇs´ıdeskriptor, pˇrizruˇsen´ıposledn´ıhodeskriptoru soketu zavˇresoket. • pro SOCK STREAM soket z´aleˇz´ına nastaven´ıpˇr´ıznaku SO LINGER (default je l onoff == 0, mˇen´ıse funkc´ı setsockopt). – l onoff == 0 . . . vol´an´ı close se vr´at´ı,ale j´adrose snaˇz´ı d´alpˇren´estzbyl´adata – l onoff == 1 && l linger != 0 . . . j´adrose snaˇz´ıpˇren´est zbyl´adata do vyprˇsen´ıtimeoutu l linger v sekund´ach, kdyˇzse to nepovede, close vr´at´ıchybu, jinak vr´at´ıOK po pˇrenesen´ıdat. – l onoff == 1 && l linger == 0 . . . provede se reset spojen´ı

• po uzavˇren´ım˚uˇzeTCP soket z˚ustatpo nˇejakou dobu v pˇrechodn´emstavu, kter´yje definov´anprotokolem TCP pˇriukonˇcov´an´ıspojen´ı.Neˇzje soket zcela zruˇsen,nelze pouˇz´ıtjin´ysoket na stejn´emportu, pokud toto nebylo pˇredt´ım povoleno nastaven´ımpˇr´ıznaku SO REUSEADDR pomoc´ıfunkce setsockopt, viz strana 195.

• reset spojen´ıje abnorm´aln´ıukonˇcen´ıspojen´ı.V TCP se pouˇzijepaket s na- staven´ympˇr´ıznakem RST. Na druh´estranˇese norm´aln´ıukonˇcen´ıspojen´ıpro- jev´ıjako konec souboru (pˇriˇcten´ı),reset zp˚usob´ıchybu ECONNRESET. Pˇr´ıklad tcp/linger.c .

196 Uzavˇren´ısoketu: shutdown()

int shutdown(int socket, int how ); • Uzavˇresoket (ale neruˇs´ıdeskriptor) podle hodnoty how: – SHUT RD . . . pro ˇcten´ı – SHUT WR . . . pro z´apis – SHUT RDWR . . . pro ˇcten´ıi z´apis

• Po uzavˇren´ı soketu pomoc´ı shutdown je nutn´ezavˇr´ıt i deskriptor pomoc´ı close. • Pˇrinorm´aln´ımukonˇcen´ıspojen´ına ´urovni protokolu TCP kaˇzd´astrana sig- nalizuje, ˇzeuˇznebude nic zapisovat. To plat´ıi v pˇr´ıpadˇepouˇzit´ı close nebo shutdown(fd, SHUT RDWR). Pˇripouˇzit´ı shutdown(fd, SHUT WR) lze ze so- ketu d´alˇc´ıst.Druh´astrana dostane EOF pˇriˇcten´ı,ale m˚uˇzed´alzapisovat.

197 Poˇrad´ıbajt˚u

• s´ıt’ov´esluˇzby pouˇz´ıvaj´ıpoˇrad´ıbajt˚u,kter´ese m˚uˇzeliˇsitod poˇrad´ıpouˇz´ıvan´ehona lok´aln´ımsyst´emu. Pro pˇrevod lze pouˇz´ıt funkce (makra): – uint32 t htonl(uint32 t hostlong ); host → s´ıt’, 32 bit˚u – uint16 t htons(uint16 t hostshort ); host → s´ıt’, 16 bit˚u – uint32 t ntohl(uint32 t netlong ); s´ıt’ → host, 32 bit˚u – uint16 t ntohs(uint16 t netshort ); s´ıt’ → host, 16 bit˚u • s´ıt’ov´epoˇrad´ıbajt˚uje big-endian, tj. nejprve vyˇsˇs´ıbajt. Pouˇz´ıv´a se hlavnˇeve funkc´ıch pracuj´ıc´ıch s adresami a ˇc´ıslyport˚u.

• pokud lok´aln´ısyst´empouˇz´ıv´astejn´epoˇrad´ıbajt˚ujako s´ıt’, nedˇelaj´ıpˇrevodn´ı funkce nic. • jednoduch´ya pˇritomvˇetˇsinoupostaˇcuj´ıc´ıtest na to, zda spr´avnˇepˇrev´ad´ıte poˇrad´ıbajt˚u,je spustit vaˇsprogram proti sobˇe(pokud to tak lze) na archi- tektur´ach s rozd´ıln´ymuspoˇr´ad´an´ımbajt˚u.

198 C´ıslaprotokol˚uaˇ port˚u

struct protoent *getprotobyname(const char *name ); • v poloˇzce p proto vr´at´ıˇc´ısloprotokolu se jm´enem name (napˇr. pro "tcp" vr´at´ı6). • ˇc´ıslaprotokol˚ujsou uloˇzenav souboru /etc/protocols.

struct servent *getservbyname(const char *name, const char *proto ); • pro zadan´ejm´enosluˇzby name a jm´enoprotokolu proto vr´at´ı v poloˇzce s port ˇc´ısloportu. • ˇc´ıslaport˚ujsou uloˇzenav souboru /etc/services. funkce vrac´ı NULL, kdyˇzv datab´azinen´ıodpov´ıdaj´ıc´ıpoloˇzka.

• v´ysledek getprotobyname se hod´ıpro vol´an´ı socket, v´ysledek getservby- name pro vol´an´ı bind. • kromˇe getservbyname existuje jeˇstˇe getservbyport umoˇzˇnuj´ıc´ıhledat sluˇzbu pomoc´ıˇc´ıslaportu (pozor, v network byte order !) a funkce getservent a spol. pro ruˇcn´ıproch´azen´ız´aznam˚u.

• vˇsechny tyto funkce prohled´avaj´ıpouze ”ofici´aln´ı”seznamy sluˇzeba proto- kol˚u,kter´ese nach´azej´ıvˇetˇsinouv souborech zm´ınˇen´ych na slajdu. • v uveden´ych souborech je definov´anomapov´an´ımezi jm´eny a ˇc´ıslypro stan- dardn´ıprotokoly a sluˇzby.

• pozor na to, ˇzeprotokolem zde nemysl´ımeHTTP, SSH, telnet nebo FTP – to jsou zde sluˇzby, reprezentovan´eˇc´ıslyport˚u.Protokol je TCP, UDP, OSPF, GRE apod., tedy to, co je pˇren´aˇsenov IP paketu v poloˇzce Protocol, viz strany 11 a 14 v RFC 791.

• pˇr´ıklad: resolving/getbyname.c

199 Pˇrevod hostname na adresy: getaddrinfo()

• ze zadan´ych parametr˚upˇr´ımogeneruje sockaddr struktury • pracuje s adresami i s porty • jej´ıchov´an´ıje ovlivniteln´epomoc´ıtzv. hint˚u int getaddrinfo(const char *nodename, const char *servicename, const struct addrinfo *hint, struct addrinfo **res ); • poloˇzkystruktury addrinfo: ai flags (pro hinty), ai family (address family), ai socktype, ai protocol, ai addrlen, struct sockaddr *ai addr (v´ysledn´eadresy), char *ai canonname, struct addrinfo *ai next (dalˇs´ıprvek v seznamu)

• Pˇrivyhodnocov´an´ı dotaz˚una adresy a jm´enase pouˇz´ıvaj´ı jmenn´esluˇzby podle konfigurace v souboru /etc/nsswitch.conf. • struktura addrinfo je definov´anav netdb.h • getaddrinfo um´ıdo struktur sockaddr pˇrev´adˇetjak ˇretˇezeckter´yobsahuje hostname, tak ˇretˇezecobsahuj´ıc´ıIP adresu. Stejnˇeje tomu i pro porty. • funkce getaddrinfo vrac´ı parametrem res seznam struktur sockaddr, ve kter´ych jsou uloˇzeny adresy koresponduj´ıc´ık dan´emu vstupu. • je rozd´ılzda budou adresn´ıstruktury d´alepouˇzity pro server nebo klient; pro server napˇr.staˇc´ıjako nodename d´at NULL (wildcard socket). Podobnˇepro pro poloˇzku ai flags struktury addrinfo pouˇzit´epro parametr hint a jej´ı hodnotu AI PASSIVE. • Po skonˇcen´ı pr´aces v´ysledky nezapomeˇntezavolat funkci freeaddrinfo, kter´auvoln´ınaalokovanou pamˇet.

• pˇr´ıklad: resolving/getaddrinfo.c • Dˇr´ıve se hodnˇepouˇz´ıvaly funkce gethostbyname a gethostbyaddr. Tyto funkce pracuj´ıpouze s IPv4 adresami a jm´eny, jsou tak povaˇzov´any za za- staral´e a jejich pouˇzit´ıse nedoporuˇcuje.M´ıstonich se doporuˇcujepouˇz´ıvat obecnˇejˇs´ıvol´an´ı getipnodebyname a getipnodebyaddr (getipnode* funkce se nach´az´ıv r˚uzn´ych syst´emech, nicm´enˇebyly ned´avnovyjmuty z GNU libc, takˇzese na jejich pˇr´ıtomnost nelze univerz´alnˇespolehnout. Nav´ıc nejsou souˇc´ast´ıUNIX standardu.) resp. getaddrinfo, getnameinfo. Z tˇechto funkc´ı pouze getaddrinfo a getnameinfo splˇnuj´ıstandard (POSIX.1-2001).

200 • Pochopitelnˇe,je nutn´edobˇreuv´aˇzit,zda existuj´ıc´ık´odpouˇz´ıvaj´ıc´ılegacy/obsolete funkce je potˇrebapˇrepisovat. Pokud takov´emu programu bude IPv4 staˇciti nad´ale,mˇenitexistuj´ıc´ıa funkˇcn´ık´odnemus´ıb´ytvˇzdyrozumn´e. Nov´yk´od ale vˇzdypiˇstepomoc´ınov´ych funkc´ı, kter´epodporuj´ıIPv4 i IPv6, i po- kud byste si mysleli, ˇzev´aˇsprogram nebude IPv6 nikdy pouˇz´ıvat. Za pouˇzit´ı gethostbyname, gethostbyaddr nebo struktur specifick´ych pro IPv4 resp. IPv6 (bez v´aˇzn´ehod˚uvodu) p˚ujdeu zkouˇskyhodnocen´ıdol˚u.

Pˇrevod adresy na hostname: getnameinfo()

• protˇejˇsekk funkci getaddrinfo • jako vstup pracuje s cel´ymi sockaddr strukturami, tedy funguje s IPv4 i IPv6 adresami, narozd´ılod funkce gethostbyaddr.

int getnameinfo(const struct sockaddr *sa, socklen t *sa len, char *nodename, socketlen t *nodelen, char *servicename, socketlen t *servicelen, unsigned flags );

• getnameinfo prov´ad´ıv jednom vol´an´ıfunkce konverzi adresy a ˇc´ıslaportu uloˇzen´ych ve struktuˇre sockaddr na stringy v z´avislostina namingov´ych sluˇzb´ach (tedy standardn´ıcesta pˇresnaming backendy v /etc/nsswitch.conf) a hodnotˇe flags. Tedy to, co by bylo postaru nutn´eprov´adˇetpomoc´ıvol´an´ı gethostbyaddr a getservbyport. • Tato funkce je narozd´ılod v´yˇsezm´ınˇen´ych legacy funkc´ıreentrantn´ıa hod´ı se tedy pro pouˇzit´ıv prostˇred´ıs thready (alespoˇnna vˇetˇsinˇesyst´em˚u).

• manu´alov´astr´anka obsahuje seznam pouˇziteln´ych NI flag˚upro flags a jejich v´yznam

• pˇr´ıklad: resolving/getnameinfo.c

201 Pˇr´ıklad:TCP server struct sockaddr storage ca; int nclients = 10, fd, nfd; struct addrinfo *r, *rorig, hi; memset(&hi, 0, sizeof (hi)); hi.ai family = AF UNSPEC; hi.ai socktype = SOCK STREAM; hi.ai flags = AI PASSIVE; getaddrinfo(NULL, portstr, &hi, &rorig); for (r = rorig; r != NULL; r = r->ai next) { fd = socket(r->ai family, r->ai socktype, r->ai protocol); if (!bind(fd, r->ai addr, r->ai addrlen)) break; } freeaddrinfo(rorig); listen(fd, nclients); for (;;) { sz = sizeof(ca); nfd = accept(fd, (struct sockaddr *)&ca, &sz); /* Komunikace s klientem */ close(newsock); }

• Toto je obecn´akostra serveru. Argument portstr je jedin´yvstupn´ıparametr. Prvn´ı´uspˇeˇsn´ybind ukonˇc´ıproch´azen´ıseznamu adres. • Takto napsan´yserver bude na syst´emu, kter´ypodporuje IPv6 i IPv4 pˇrij´ımat spojen´ıv obou adresn´ıch rodin´ach na tomt´eˇzsocketu. Spojen´ız IPv4 klient˚u budou m´ıtjako zdrojovou adresu tzv. IPv4-mapped IPv6 adresu, kter´av sobˇe obsahuje IPv4 adresu (napˇr. ::FFFF:78.128.192.1). • Vˇsimnˇetesi, ˇzenen´ı nutn´et´emˇeˇr nic pˇretypov´avat na pointer na struk- turu sockaddr. Jedinou v´yjimkou je vol´an´ı accept. Pro vol´an´ı accept se pouˇz´ıv´astruktura typu sockaddr storage coˇzje obecn´y”kontejner”schopn´y pojmout prvky struktury sockaddr in i sockaddr in6.

• socket a bind se volaj´ıpro vˇsechny vr´acen´e sockaddr struktury dokud pro jednu z nich bind neuspˇejenebo se seznam nevyˇcerp´a. • Probl´em:nekontroluj´ı se nˇekter´en´avratov´ehodnoty a neobsahuje vol´an´ı uvolˇnuj´ıc´ıalokovan´eentity, napˇr.uzavˇren´ısocketu v pˇr´ıpadˇechyby vol´an´ı bind. Stejnˇetak se neˇreˇs´ısituace kdy se vyˇcerp´aseznam bez toho aby bind uspˇel(to lze detekovat pomoc´ıkontroly nenulovosti pointeru r za koncem prvn´ıhocyklu).

202 Pˇr´ıklad:TCP klient

int fd; struct addrinfo *r, *rorig, hi; memset(&hi, 0, sizeof (hi)); hi.ai family = AF UNSPEC; hi.ai socktype = SOCK STREAM; getaddrinfo(hoststr, portstr, &hi, &r); for (rorig = r; r != NULL; r = r->ai next) { fd = socket(r->ai family, r->ai socktype, r->ai protocol); if (connect(fd, (struct sockaddr *)r->ai addr, r->ai addrlen) == 0) break; } freeaddrinfo(resorig); /* Komunikace se serverem */ close(fd);

• Toto je obecn´akostra TCP klienta. Argumenty hoststr a portstr jsou jedin´evstupn´ıparametry. Prvn´ı´uspˇeˇsn´y connect ukonˇc´ıproch´azen´ıadres pro dan´yhost. • V pˇr´ıkladuvyuˇz´ıv´ameautomatick´ehopˇridˇelen´ıvoln´ehoportu syst´emempˇri vol´an´ı connect (nepˇredch´azelomu vol´an´ı bind).

• postupnˇese vol´a connect na vˇsechny vr´acen´e sockaddr struktury (v addrinfo struktur´ach) pro dan´yhost do t´edoby, neˇzse podaˇr´ıspojit. • Probl´em:neobsahuje kontrolu n´avratov´ych hodnot vol´an´ı.Stejnˇetak se neˇreˇs´ı situace kdy se vyˇcerp´aseznam bez toho aby connect uspˇel(to lze detekovat pomoc´ıkontroly nenulovosti pointeru r za koncem prvn´ıhocyklu). Nebo se neuzav´ır´asocket pˇrine´uspˇeˇsn´emvol´an´ı connect, tj. je to file descriptor leak.

203 Cek´an´ınaˇ data: select()

int select(int nfds, fd set *readfds, fd set *writefds, fd set *errorfds, struct timeval *timeout ); • zjist´ı,kter´eze zadan´ych deskriptor˚ujsou pˇripraveny pro ˇcten´ı, z´apis,nebo na kter´ych doˇslok v´yjimeˇcn´emu stavu. Pokud ˇz´adn´ytakov´ydeskriptor nen´ı,ˇcek´ado vyprˇsen´ıˇcasu timeout (NULL . . . ˇcek´ase libovolnˇedlouho). Parametr nfds ud´av´a rozsah testovan´ych deskriptor˚u(0, ..., nfds-1). • pro nastaven´ıa test masek deskriptor˚uslouˇz´ıfunkce: – void FD ZERO(fd set *fdset ) . . . inicializace – void FD SET(int fd, fd set *fdset ) . . . nastaven´ı – void FD CLR(int fd, fd set *fdset ) . . . zruˇsen´ı – int FD ISSET(int fd, fd set *fdset ) . . . test

• Motivace: jestliˇzechceme ˇc´ıst data z v´ıcedeskriptor˚u,je moˇzn´e,pokud jde o soubor, rovnou jej otevˇr´ıts pˇr´ıznakem O NONBLOCK, anebo tento pˇr´ıznak kdykoli nastavit na deskriptoru pomoc´ı vol´an´ı fncnl s druh´ymparamet- rem O SETFL (ne O SETFD, viz strana 104). Neblokuj´ıc´ım read pak stˇr´ıdavˇe testujeme jednotliv´edeskriptory, a mezi kaˇzd´ymkolem test˚utˇrebapouˇz´ıt sleep(1). Nev´yhody jsou aktivn´ıˇcek´an´ı,reˇziepˇrep´ın´an´ımezi m´odemuˇziva- telsk´yma j´adra,moˇzn´aprodleva (aˇzdo d´elkyvaˇsehoˇcek´an´ımezi jednotliv´ymi koly), a tak´eto, ˇzenesloˇz´ıtezkouˇsku(viz strana 167). Spr´avn´eˇreˇsen´ıt´eto situace je pouˇz´ıtnapˇr´ıklad select a n´aslednˇezavolat read na ty deskriptory, kter´evol´an´ı select ohl´as´ıjako pˇripraven´e.

• Pˇr´ıkladna busy waiting: select/busy-wait.c . Vˇsimnˇetesi, ˇzenovˇevy- tvoˇren´ysoket v pˇr´ıkladuje bez flagu O NONBLOCK, viz strana 190, takˇzeje nutn´eflag nastavit. • Pˇripraven´y (ready) znamen´a,ˇze read nebo write s vynulovan´ympˇr´ıznakem O NONBLOCK by se nezablokovalo, tedy ne nutnˇeˇzenˇejak´adata jsou pˇripra- vena (read napˇr.m˚uˇzevr´atit0 pro end-of-file nebo -1 pro chybu) • Mnoˇzina errorfds je pro v´yj´ımkyv z´avislostina typu deskriptoru; pro socket to je napˇr´ıkladpˇr´ıchod urgentn´ıch dat (flag URG v TCP hlaviˇcce). Neznamen´a to, ˇzena dan´emdeskriptoru doˇslok chybˇe! Chyba s nastaven´ym errno se zjist´ız ostatn´ıch mnoˇzinpo n´avratov´emk´odu-1 proveden´ehovol´an´ı,tj. napˇr´ıklad read. • Pˇrivol´an´ıjsou v mnoˇzin´ach deskriptory, kter´echceme testovat, po n´avratu z˚ustanounastaven´ejen ty deskriptory, na kter´ych nastala testovan´aud´alost.

204 Je nutn´eje tedy pˇreddalˇs´ımvol´an´ım select znovu nastavit. Typicky to jsou bitov´emasky, ale nemus´ıtomu b´yttak; z pozice program´atoraje to samozˇrejmˇejedno. Proch´azen´ıpˇresvr´acen´emnoˇziny je nutn´edˇelatpo jednom deskriptoru, pˇres FD ISSET. • Funkce select je pouˇziteln´ai pro ˇcek´an´ına moˇznost z´apisudo roury nebo soketu – ˇcek´ase, aˇzdruh´astrana nˇeco pˇreˇctea uvoln´ıse m´ıstov bufferu pro dalˇs´ıdata.

• M´ıstomnoˇziny pro deskriptory je moˇzn´euv´estNULL, speci´aln´ıpˇr´ıpadpˇri nastaven´ı vˇsech mnoˇzinna NULL je vol´an´ı, kter´ese pouze zablokuje do pˇr´ıchodu sign´alunebo do vyprˇsen´ıtime-outu. • Po n´avratuje nutn´eotestovat kaˇzd´ydeskriptor zvl´aˇst’, nen´ık dispozici vol´an´ı, kter´eby v´amvytvoˇrilomnoˇzinu pˇripraven´ych deskriptor˚u.

• Pokud obsluhuje s´ıt’ov´yserver v´ıceport˚u,m˚uˇzevolat select na pˇr´ısluˇsn´e deskriptory soket˚ua n´aslednˇe accept na deskriptory, pro kter´e select ohl´asil pˇr´ıchod ˇz´adostiklienta (pˇripravenost ke ˇcten´ı).

• Vol´an´ı connect na neblokuj´ıc´ımsoketu se hned vr´at´ı,nav´az´an´ıspojen´ıohl´as´ı n´asledn´y select jako pˇripravenost k z´apisu.V´ıceviz strana 192.

• Dalˇs´ımoˇznostpouˇzit´ı select je s´ıt’ov´yserver, kter´yv jednom procesu ob- sluhuje paralelnˇenˇekolik klient˚u.Pomoc´ı select se testuje stav deskriptor˚u odpov´ıdaj´ıc´ıch spojen´ıs jednotliv´ymiklienty a pˇresdeskriptory pˇripraven´e pro ˇcten´ı/z´apis se komunikuje. Aby se mohli pˇripojovat nov´ıklienti, testuje se i deskriptor soketu, kter´yse pouˇz´ıv´apro accept. Vyuˇz´ıv´ase toho, ˇze select ohl´as´ıdeskriptor s ˇcekaj´ıc´ıˇz´adost´ıklienta o spojen´ıjako pˇripraven´ypro ˇcten´ı. Na takov´ydeskriptor je moˇzn´evolat accept. • Pozor na to, ˇze select m˚uˇze zmˇenitstrukturu timeval, existuje nov´evol´an´ı pselect, kter´ekromˇedalˇs´ıch zmˇenstrukturu pro timeout nezmˇen´ı.

• Pro nfds je moˇzn´epouˇz´ıt FD SETSIZE, coˇzje syst´emov´akonstanta pro ma- xim´aln´ıpoˇcetdeskriptor˚u.Nen´ıto ale nejlepˇs´ıˇreˇsen´ı,protoˇzetato konstanta je sice vˇetˇsinoujen 1024 na 32-bitov´ych syst´emech, na Solarisu to vˇsakpro 64-bitov´earchitektury je uˇz65536. Pˇredpokl´ad´ampodobn´echov´an´ı i pro ostatn´ısyst´emy. • Pokud se ˇcasnastav´ı na 0, tedy ted’ nemluv´ıme o nastaven´ı ukazatele na NULL, select se d´apouˇz´ıtpro tzv. polling – zjist´ısouˇcasn´ystav a hned se vr´at´ı.

• Pˇr´ıklad: select/select.c

• select lze pouˇz´ıtna zjiˇst’ov´an´ıstavu po vol´an´ı connect na neblokuj´ıc´ısocket. Zda spojen´ıprobˇehlo´uspˇeˇsnˇese dozv´ıtez funkce getsockopt s opt name na- staven´ymna SO ERROR, viz strana 195. Pˇr´ıklad: tcp/non-blocking-connect.c .

205 Pˇr´ıklad:pouˇzit´ı select()

• Deskriptor fd odkazuje na soket, pˇrepisujes´ıt’ovou komunikaci na termin´ala naopak. int sz; fd set rfdset, efdset; char buf[BUFSZ]; for(;;) { FD ZERO(&rfdset); FD SET(0, &rfdset); FD SET(fd, &rfdset); efdset = rfdset; select(fd+1, &rfdset, NULL, &efdset, NULL); if(FD ISSET(0, &efdset)) /* V´yjimkana stdin */ ; if(FD ISSET(fd, &efdset)) /* V´yjimkana fd */ ; if(FD ISSET(0, &rfdset)) { sz = read(0, buf, BUFSZ); write(fd, buf, sz); } if(FD ISSET(fd, &rfdset)) { sz = read(fd, buf, BUFSZ); write(1,buf,sz); } }

• Zde je typick´epouˇzit´ı select, kdy je tˇrebaˇc´ıstdata souˇcasnˇeze dvou zdroj˚u. Tento pˇr´ıkladpˇredpokl´ad´a,ˇzedeskriptory 0 a fd jsou nastaveny jako neblo- kuj´ıc´ı.

• Pˇredkaˇzd´ymvol´an´ım select se mus´ıznovu nastavit mnoˇziny deskriptor˚u.

• Lepˇs´ıˇreˇsen´ı je pouˇz´ıt select i na z´apis.Logika ˇr´ızen´ı je pak takov´a,ˇze pro kaˇzd´ysmˇerdatov´ekomunikace m´amesamostatn´ybuffer. Pˇr´ısluˇsn´yˇctec´ı deskriptor bude v mnoˇzinˇepro ˇcten´ıv select, pr´avˇekdyˇzje buffer pr´azdn´y. Naopak z´apisov´ydeskriptor bude v mnoˇzinˇepro z´apis,pr´avˇekdyˇzje buffer nepr´azdn´y.

• select usp´ıproces i pˇrikontrole pˇripravenosti k z´apisu,pokud data nejsou z druh´estrany ˇctena.To jde jednoduˇsenasimulovat pomoc´ıprogramu, kter´yse jen pˇripoj´ı(provede TCP handshake), ale nic neˇcte.Viz pˇr´ıklada koment´aˇr v select/write-select.c .

206 Cek´an´ınaˇ data: poll()

int poll(struct pollfd fds [], nfds t nfds, int timeout ); • ˇcek´ana ud´alostna nˇekter´emz deskriptor˚uv poli fds o nfds prvc´ıch po dobu timeout ms (0 . . . vr´at´ıse hned, -1 . . . ˇcek´a se libovolnˇedlouho).

• prvky struktury pollfd: – fd . . . ˇc´ıslodeskriptoru – events . . . oˇcek´avan´eud´alosti,OR-kombinace POLLIN (lze ˇc´ıst), POLLOUT (lze ps´at),atd. – revents . . . ud´alosti,kter´enastaly, pˇr´ıznakyjako v events, nav´ıcnapˇr. POLLERR (nastala chyba)

• Tato funkce je obdoba vol´an´ı select. • argument timeout je v milisekund´ach • Existuj´ıc´ıch pˇr´ıznak˚upro pouˇzit´ıje mnohem v´ıce,viz manu´alov´astr´anka.

• Na Solarisu je poll syst´emov´evol´an´ı, select pak knihovn´ıfunkce imple- mentovan´apomoc´ı poll, a poll je tam preferov´ano. poll je nutn´epouˇz´ıtv pˇr´ıpadˇe,ˇzechcete testovat deskriptor vˇetˇs´ınebo rovn´y FD SETSIZE. To je hlavn´ırozd´ılmezi vol´an´ımi select a poll. Dalˇs´ırozd´ılje ten, ˇzenen´ı tˇrebanastavovat deskriptory po kaˇzd´emvol´an´ı poll, ani nulovat revents. • Casˇ nastaven´yna -1 je to sam´ejako NULL u select.

• Pokud nastav´ıtepoˇcet deskriptor˚una 0 (a mˇeli byste pak pro fds pouˇz´ıt NULL), m˚uˇzete poll jednoduˇsevyuˇz´ıtpro ˇcek´an´ıs menˇs´ıgranularitou neˇzpo sekund´ach nab´ızen´evol´an´ım sleep. Pˇr´ıklad: sleep/poll-sleep.c Tento ”trik”ovˇsemnefunguje na macOS, takˇzese na nˇej nelze spol´ehat. – Mimochodem, jin´yzp˚usob,jak dos´ahnoutmenˇs´ıgranularity neˇzje jedna sekunda je vol´an´ı nanosleep, kter´eje ale definovan´erozˇs´ıˇren´ımPOSIX.4 a tedy nemus´ıb´ytvˇzdyk dispozici. Pˇr´ıklad: sleep/nanosleep.c .

207 Spr´ava s´ıt’ov´ych sluˇzeb: inetd

• servery s´ıt’ov´ych sluˇzebse spouˇst´ıbud’ pˇristartu syst´emu, nebo je startuje d´emon inetd pˇripˇripojen´ıklienta. • d´emon inetd ˇcek´ana portech definovan´ych v /etc/inetd.conf a kdyˇzdetekuje pˇr´ıchoz´ıspojen´ı/datagram, spust´ıpˇr´ısluˇsn´yserver a pˇresmˇeruje mu deskriptory. • pˇr´ıkladobsahu /etc/inetd.conf: ftp stream tcp nowait root /usr/etc/ftpd ftpd -l shell stream tcp nowait root /usr/etc/rshd rshd -L login stream tcp nowait root /usr/etc/rlogind rlogind exec stream tcp nowait root /usr/etc/rexecd rexecd finger stream tcp nowait guest /usr/etc/fingerd fingerd ntalk dgram udp wait root /usr/etc/talkd talkd tcpmux stream tcp nowait root internal echo stream tcp nowait root internal

• inetd je v podstatˇevelk´y poll cyklus obhospodaˇruj´ıc´ısadu socket˚upodle konfigurace.

• Start pˇres inetd ˇsetˇr´ı prostˇredky, protoˇzepˇr´ısluˇsn´yserver bˇeˇz´ı pouze po ˇcas,kdy jsou jeho sluˇzby opravdu potˇreba.Nehod´ıse tedy pro pro spoustˇen´ı vyt´ıˇzen´ych sluˇzeb(HTTP) nebo sluˇzebkde m˚uˇzeb´ytvelk´yoverhead pˇri inicializaci (napˇr.SSH).

• Typicky se pomoc´ı inetd spouˇst´ıservery, kter´ese pouˇz´ıvaj´ım´alonebo jejichˇz inicializace je relativnˇenen´aroˇcn´a(telnetd, ftpd). Silnˇevyt´ıˇzen´ea dlouho startuj´ıc´ıservery (httpd) se obvykle startuj´ıze syst´emov´ych inicializaˇcn´ıch skript˚ua bˇeˇz´ıst´ale.

• Castoˇ m´acenu m´ıt inetd vypnut´y´uplnˇe.Pokud na vaˇsemstroji bˇeˇz´ınapˇr. pouze SSH, tak pro to se inetd ve vˇetˇsinˇepˇr´ıpad˚unepouˇz´ıv´a, inetd by byl jen dalˇs´ımserverem bˇeˇz´ıc´ımna stroji a zdroj potenci´aln´ıhonebezpeˇc´ı,pokud by se v nˇemnebo v jednom z nˇejspouˇstˇen´ych program˚uobjevila bezpeˇcnostn´ı chyba. To by ostatnˇemˇeloplatit pro vˇsechny instalovan´eprogramy posky- tuj´ıc´ıs´ıt’ov´esluˇzby - bud’to by mˇelyimplicitnˇeposlouchat pouze na localhostu (resp. pouˇz´ıvat unixov´esockety) nebo by implicitnˇenemˇelybˇeˇzet a mˇelyby b´ytspuˇstˇeny (ve smyslu permanentnˇezapnuty) aˇztehdy kdyˇzjsou skuteˇcnˇe tˇreba(tento pˇr´ıstupse oznaˇcujejako secure by default).

208 Form´atsouboru /etc/inetd.conf

sluˇzbasoket proto ˇcek´an´ıuˇzivserver argumenty • sluˇzba . . . jm´enos´ıt’ov´esluˇzby podle /etc/services • soket ... stream nebo dgram • proto . . . komunikaˇcn´ıprotokol (tcp, udp) • ˇcek´an´ı ... wait (inetd ˇcek´ana ukonˇcen´ıserveru pˇred akceptov´an´ımdalˇs´ıhoklienta), nowait (inetd akceptuje dalˇs´ıhoklienta hned) • uˇzivatel . . . server pobˇeˇz´ıs identitou tohoto uˇzivatele • server . . . ´upln´acesta k programu serveru nebo internal (sluˇzbuzajiˇst’uje inetd) • argumenty . . . pˇr´ıkazov´yˇr´adekpro server, vˇcetnˇe argv[0]

• Soket typu stream: – wait . . . server dostane soket, na kter´ymus´ı aspoˇnjednou zavolat accept. Teprve t´ımz´ısk´anov´ysoket, pˇreskter´ym˚uˇzekomunikovat s klientem. Po skonˇcen´ıserveru pˇreb´ır´aˇr´ızen´ısoketu zpˇet inetd. – nowait ... inetd zavol´a accept a z´ıskan´ysoket pˇred´aserveru, ser- ver tedy m˚uˇzerovnou komunikovat (m˚uˇzepouˇz´ıvat standardn´ıvstup a v´ystup)a nemus´ıvˇedˇet,ˇzekomunikuje po s´ıti.Mezit´ım inetd ˇcek´ana dalˇs´ıklienty a podle potˇreby spouˇst´ıdalˇs´ıinstance serveru. • Jak pro wait tak pro nowait provedl inetd na soketu vol´an´ı bind aby mu pˇriˇradilˇc´ısloportu podle pole sluˇzba. • V pˇr´ıpadˇe wait dostane server soket od inetd v podobˇedeskriptoru 0 (stan- darn´ıvstup). inetd pˇredvol´an´ım fork provedl dup2(sock, 0), kde sock je nabindovan´ysocket. Viz pˇr´ıklad inetd/accept-rw.c .

• V pˇr´ıpadˇe nowait inetd zavol´a accept (pro TCP spojen´ı),pˇresmˇerujedeskrip- tory 0, 1, a 2 do s´ıt’ov´ehosocketu a spust´ıdan´yserver. Viz pˇr´ıklad: inetd/echo-server.sh . Pod´ıvejte se do dan´ehoskriptu pro podrobn´einstrukce, jak ho pouˇz´ıt. • Pro soket typu dgram m´asmysl pouze wait. Server mus´ıpˇreˇc´ıstze soketu aspoˇnjeden datagram. • Jestliˇze inetd restartuje server (kromˇe stream nowait) pˇr´ıliˇsˇcasto(cca jed- nou za sekundu), usoud´ı,ˇzenastala chyba a po urˇcitoudobu (asi 10 minut) sluˇzbuzablokuje (nespouˇst´ıserver a odm´ıt´aspojen´ı).Ostatn´ıservery spouˇst´ı norm´alnˇed´al.

209 • Pro zaj´ımavost, ne vˇsechny syst´emy mus´ınutnˇe inetd.conf pouˇz´ıvat stejn´ym zp˚usobem. Napˇr´ıkladod Solarisu 10 se tento soubor pouˇzijepouze pro po- ˇc´ateˇcn´ıkonverzi do intern´ıdatab´azepomoc´ı inetconv(1M) a pro zap´ın´an´ıa vyp´ın´an´ısluˇzebse pak pouˇz´ıv´apˇr´ıkaz inetadm(1M).

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´emsoubor˚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´anopozdˇeji,podle toho kolik zbyde ˇcasu

210 Vl´akna • vl´akno(thread) = linie v´ypoˇctu(thread of execution) • vl´aknaumoˇzˇnuj´ım´ıtv´ıcelini´ıv´ypoˇctuv r´amcijednoho procesu • klasick´yunixov´ymodel: jednovl´aknov´eprocesy • vl´aknanejsou vhodn´apro vˇsechny aplikace • v´yhody vl´aken: – zrychlen´ıaplikace, typicky na v´ıceprocesorech (vl´akna jednoho procesu mohou bˇeˇzetsouˇcasnˇena r˚uzn´ych procesorech) – modul´arn´ıprogramov´an´ı • nev´yhody vl´aken: – nen´ıjednoduch´ekorektnˇenapsat sloˇzitˇejˇs´ık´ods vl´akny – obt´ıˇznˇejˇs´ıdebugging

• Pro aplikace, kde kaˇzd´ykrok z´avis´ına kroku pˇredch´azej´ıc´ım,nemaj´ıvl´akna pˇr´ıliˇsvelk´ysmysl. • Debuggery typicky maj´ıpodporu vl´aken, ale debugging zmˇen´ıtiming, takˇze to co v re´aludˇel´aprobl´emse pˇridebuggingu v˚ubec nemus´ıprojevit. Toto vˇetˇsinounen´ıprobl´emem u klasick´ych 1-vl´aknov´ych proces˚u.

• Jak bylo uvedeno na slajdech s doporuˇcenouliteraturou, k vl´akn˚umexis- tuje v´yborn´akniha [Butenhof]. On-line pak je tˇrebadostupn´aobs´ahl´akniha Multithreaded Programming Guide na http://docs.oracle.com. • Dalˇs´ısituac´ı,kdy je potˇrebaz˚ustatu pouˇzit´ıproces˚u,je pokud je nutn´evytvo- ˇren´ymproces˚ummˇenitre´aln´ea efektivn´ıUID. To je tˇrebapˇr´ıpadOpenSSH, kde se pro kaˇzd´espojen´ıvytvoˇr´ıdva server procesy. Jeden proces bˇeˇz´ıs ma- xim´aln´ımiprivilegii, typicky jako root, a poskytuje sluˇzby neprivilegovan´emu procesu bˇeˇz´ıc´ım pod pˇrihl´aˇsen´ymuˇzivatelem. Takovou sluˇzbou je tˇrebaalo- kace presudo termin´alu,coˇzpod bˇeˇzn´ymuˇzivatelem nelze prov´est.Idea je takov´a,ˇzevˇetˇsinak´oduprivilegia roota nepotˇrebuje,ˇc´ımˇzse v´yraznˇezmenˇs´ı mnoˇzstv´ık´odu,kde by chyba vedla k z´ısk´an´ıprivilegi´ıroota. Tento zp˚usobse naz´yv´a privilege separation a nen´ımoˇzn´eho dos´ahnoutpomoc´ıvl´aken tak, ˇze by r˚uzn´avl´aknabˇeˇzelapod r˚uzn´ymiuˇzivateli, protoˇzevˇsechna vl´aknasd´ılej´ı stejn´yadresov´yprostor, a kaˇzd´eho tak m˚uˇzemˇenit.

211 Implementace vl´aken

library-thread model • vl´aknajsou implementov´anav knihovn´ach, j´adroje nevid´ı. • run-time knihovna pl´anuje vl´aknana procesy a j´adro pl´anuje procesy na procesory. ⊕ menˇs´ıreˇziepˇrep´ın´an´ıkontextu nem˚uˇzebˇeˇzet v´ıcevl´aken stejn´ehoprocesu najednou. kernel-thread model • vl´aknajsou implementov´anapˇr´ımoj´adrem. ⊕ v´ıcevl´aken jednoho procesu m˚uˇzebˇeˇzetnajednou na r˚uzn´ych procesorech. pl´anov´an´ıthread˚upouˇz´ıv´asyst´emov´avol´an´ım´ısto knihovn´ıch funkc´ı,t´ımv´ıcezatˇeˇzujesyst´em. hybridn´ımodely • vl´aknase multiplexuj´ına nˇekolik j´adrempl´anovan´ych entit.

• p˚uvodnˇeUNIX s vl´akny nepracoval a prvn´ıimplementace byly ˇcistˇeknihovn´ı, bez ´uˇcastij´adra.Dnes se pouˇz´ıv´asp´ıˇse implementace vl´aken v j´adrunebo sm´ıˇsen´ymodel. • zat´ımcopˇripr´acis v´ıceprocesy je nutn´evyvinout jist´e´usil´ıproto, aby dan´eprocesy mohly data sd´ılet,u vl´aken je naopak nutn´eˇreˇsit situaci, jak pˇrirozen´esd´ılen´ıdat uhl´ıdat. • vl´aknaimplementov´anapouze v knihovnˇemohou b´ytpreemptivn´ıi nepre- emptivn´ı.Pro preemptivnost je moˇzn´epouˇz´ıtˇcasovaˇcea sign´aly. Pokud mul- tithreading (= pouˇzit´ı vl´aken v aplikaci) nen´ı pouˇzitpro zv´yˇsen´ı v´ykonu aplikace, typicky nen´ıprobl´ems pouˇzit´ımnepreemptivn´ıch vl´aken. Stˇr´ıd´an´ı vl´aken se automaticky dos´ahnepouˇz´ıv´an´ımblokuj´ıc´ıch syst´emov´ych vol´an´ı. • pokud se vol´an´ıv library-thread modelu zablokuje, zablokuje se cel´yproces, tj. ˇz´adn´evl´aknonem˚uˇzebˇeˇzet.To vypl´yv´az toho, ˇzej´adrov tomto mo- delu o pojmu vl´aknonic nev´ı.Knihovn´ıfunkce jsou proto pˇreps´any tak, ˇze m´ıstoblokuj´ıc´ıch vol´an´ıse pouˇzij´ıneblokuj´ıc´ı,aktu´aln´ıkontext se uloˇz´ıa n´aslednˇepˇrepnena jin´evl´aknopomoc´ıvol´an´ı setjmp a longjmp. Pˇr´ıklad: pthreads/setjmp.c .

212 POSIX vl´akna(pthreads)

• definovan´erozˇs´ıˇren´ımPOSIX.1c

• vol´an´ıt´ykaj´ıc´ıse vl´aken zaˇc´ınaj´ıprefixem pthread • tyto funkce vrac´ı0 (OK) nebo pˇr´ımoˇc´ıslochyby – . . . a nenastavuj´ı errno! – nelze s nimi proto pouˇz´ıtfunkce perror nebo err • POSIX.1c definuje i dalˇs´ıfunkce, napˇr´ıkladnov´everze k tˇem, kter´enebylo moˇzn´eupravit pro pouˇzit´ıve vl´aknech bez zmˇeny API, napˇr readdir r, strtok r, atd. – r znamen´a reentrant, tedy ˇzefunkci m˚uˇze volat v´ıcevl´aken najednou bez vedlejˇs´ıch efekt˚u

• Obecn´einformace o POSIXu jsou na stranˇe 15. • Existuj´ıi dalˇs´ıimplementace vl´aken podporuj´ıc´ırozd´ıln´aAPI, napˇr.syst´e- mov´evol´an´ı sproc() v IRIXu, Cthreads, Solaris threads, . . . • API pro POSIX vl´akna jsou na r˚uzn´ych syst´emech k dispozici v r˚uzn´ych knihovn´ach. Napˇr.na Linuxu je nutn´eprogramy pouˇz´ıvaj´ıc´ıPOSIX threads API linkovat s -lpthread, na Solarisu jsou funkce souˇc´ast´ı libc. • Implementace POSIX threads je vˇetˇsinoupostavena nad nativn´ıimplemen- tac´ıthread˚una dan´emsyst´emu, napˇr.na Solarisu nad funkcemi s prefixem thr . • O reentrantn´ıch funkc´ıch ve spojen´ıs vl´akny v´ıcena stranˇe 239

• Co se t´yk´aoˇsetˇren´ın´avratov´ych hodnot pthread funkc´ı,tak vzhledem k tomu, ˇze nenastavuj´ı errno, nen´ın´asleduj´ıc´ık´odnaps´ankorektnˇe:

if (pthread_create(&thr, NULL, thrfn, NULL) != 0) err(1, "pthread_create");

protoˇzeprogram v´ampˇrichybˇevyp´ıˇsenˇecojako:

– “a.out: pthread create: Error 0” na Solarisu – “a.out: pthread create: Success” na Linuxov´ych distribuc´ıch – “a.out: pthread create: Unknown error: 0” na FreeBSD

213 – nebo nˇecojin´eho,podle syst´emu, kter´yzrovna pouˇz´ıv´ate Trochu matouc´ımi pˇrijdepˇr´ıstupLinuxu, protoˇzena prvn´ıpohled nen´ıjasn´e, co se vlastnˇestalo a ˇze errno bylo nulov´e.Nicm´enˇe,spr´avnˇenapsan´yk´odje napˇr´ıkladtento:

int e; if ((e = pthread_create(&thr, NULL, thrfn, NULL)) != 0) errx(1, "pthread_create: %s", strerror(e));

Vˇsimnˇetesi nutnosti pouˇz´ıt errx funkci, ne err, protoˇzeta internˇepracuje s errno. Pozor na to, ˇze promˇenn´a errno by v˚ubec nemusela b´ytnulov´a, pokud by ji nastavila jin´afunkce volan´apˇred pthread create, coˇzby mohlo uˇzivatele nebo program´atorazm´astjeˇstˇev´ıce. • Ostatn´ı funkce, kter´e errno nastavuj´ı, funguj´ı stejnˇei s vl´akny, tj. kaˇzd´e vl´aknom´asvoj´ı errno. Pozor je ale tˇrebad´atna to, ˇzer˚uzn´esyst´emy se cho- vaj´ır˚uznˇe.Na Linuxu je errno automaticky thread-safe protoˇzetam mus´ıte specifikovat vl´aknovou knihovnu, na Solarisu ale mus´ıteu Sun Studia pouˇz´ıt pˇrep´ınaˇc -mt nebo -D REENTRANT, viz manu´alov´astr´anka threads(5). Po- kud tak neudˇel´ate,nebude errno nastaveno korektnˇe.Pod´ıvejte se na de- finici errno v /usr/include/errno.h a pochop´ıte, jak to funguje. Dalˇs´ı rozd´ılje ten, ˇzeSolaris m´avl´aknapˇr´ımov libc, u ostatn´ıch syst´em˚umus´ıte vˇetˇsinoutspecifikovat vl´aknovou knihovnu. U gcc staˇc´ına jak´emkoli syst´emu pouˇz´ıtpˇrep´ınaˇc -pthreads, potˇrebnouknihovnu si pˇrekladaˇcuˇznajde s´am, a z´aroveˇnnastav´ı errno jako thread-safe. Stejnˇejako u cc je ale na Solarisu moˇzn´epouˇz´ıtjen -D REENTRANT.

Vytvoˇren´ıvl´akna

int pthread create(pthread t *thread, const pthread attr t *attr, void *(*start fun )(void*), void *arg ); • vytvoˇr´ınov´evl´akno,do thread uloˇz´ıjeho ID. • podle attr nastav´ıjeho atributy, napˇr.velikost z´asobn´ıkuˇci pl´anovac´ıpolitiku. NULL znamen´apouˇz´ıtimplicitn´ıatributy. • ve vytvoˇren´emvl´aknu spust´ıfunkci start fun() s argumentem arg. Po n´avratuz t´etofunkce se zruˇs´ıvl´akno. • s objekty pthread attr t lze manipulovat funkcemi pthread attr init(), pthread attr destroy(), pthread attr setstackaddr(), atd. . .

214 • Pozor na konstrukce typu:

for (i = 0; i < N; i++) pthread create(&tid, attr, start routine, &i);

Na prvn´ıpohled takto pˇred´amekaˇzd´emu vl´aknu jeho index. Jenˇzepl´anovaˇc m˚uˇzezp˚usobitto, ˇzeneˇzsi novˇespuˇstˇen´evl´aknostaˇc´ıpˇreˇc´ısthodnotu i, pˇr´ıkaz for provede dalˇs´ıiteraci a hodnota se zmˇen´ı.Obecnˇevl´aknom˚uˇze dostat m´ıstospr´avn´ehodnoty i libovolnou vˇetˇs´ı.

• Pˇr´ıklady: pthreads/wrong-use-of-arg.c , pthreads/correct-use-of-arg.c .

• Co je moˇzn´epouˇz´ıt,pokud potˇrebujemepˇredatpouze jednu hodnotu (podle C standardu je to ale implementaˇcnˇez´avisl´ea tedy nepˇrenositeln´e):

assert(sizeof (void *) >= sizeof (int)); for (i = 0; i < N; i++) pthread create(&tid, attr, start routine, (void *)(intptr t)i);

. . . a ve funkci void *start routine(void *arg) pak pˇretypovat ukazatel zp´atkyna integer a m´ame potˇrebn´yidentifik´atorvl´akna:

printf("thread %d started\n", (int)arg);

Pˇr´ıklad: pthreads/int-as-arg.c

• Pokud potˇrebujemepˇredatv´ıcebajt˚uneˇzje velikost ukazatele, tak uˇzopravdu mus´ıme pˇredat ukazatel na pamˇet’ s pˇr´ısluˇsn´ymipˇred´avan´ymidaty nebo pouˇz´ıtglob´aln´ıpromˇenn´e;pˇr´ıstupk nim je pak ale samozˇrejmˇenutn´esyn- chronizovat.

• pthread t je ”pr˚uhledn´y”typ, do kter´ehoprogram nevid´ıa ani by nemˇel, jeho implementace se m˚uˇzeliˇsitsyst´emod syst´emu; nicm´enˇevˇetˇsinoujde o celoˇc´ıseln´ytyp, kter´yse pouˇz´ıv´ak mapov´an´ına nativn´ıthready na dan´em syst´emu. Pˇrivytv´aˇren´ınˇekolika thread˚uv cyklu je tedy nutn´epˇredatfunkci pthread create pokaˇzd´eadresu jin´epromˇenn´e pthread t, jinak uˇznep˚ujde s tˇemitovl´akny nad´alemanipulovat z hlavn´ıhovl´akna,napˇr.ˇcekat na jejich dokonˇcen´ı(aˇckoliv bˇeˇzetbudou norm´alnˇe),jejich identifikace se ztrat´ı.Toto je ˇreˇsiteln´enapˇr.pˇrespole pthread t nebo dynamickou alokac´ı.

215 Soukrom´eatributy vl´aken

• ˇc´ıtaˇcinstrukc´ı • z´asobn´ık(automatick´epromˇenn´e) • thread ID, dostupn´efunkc´ı pthread t pthread self(void); • pl´anovac´ıpriorita a politika • hodnota errno • kl´ıˇcovan´ehodnoty – dvojice (pthread key t key, void *ptr ) – kl´ıˇcvytvoˇren´yvol´an´ım pthread key create() je viditeln´y ve vˇsech vl´aknech procesu. – v kaˇzd´emvl´aknu m˚uˇzeb´yts kl´ıˇcemasociov´ana jin´ahodnota vol´an´ım pthread setspecific().

• Kaˇzd´evl´aknom´az´asobn´ıkpevn´evelikosti, kter´yse automaticky nezvˇet- ˇsuje. B´yv´ato kolem 64-512 KB, takˇzepokud si ve funkci alokujete pole o velikosti 256KB a pouˇzijeteho, je dost moˇzn´e,ˇzeskonˇc´ıtes core dumpem. Pokud chcete z´asobn´ıkvˇetˇs´ıneˇzje syst´emov´ydefault, mus´ıtepouˇz´ıtargument attr pˇrivytvoˇren´ıvl´akna.Pˇr´ıklad: pthreads/pthread-stack-overflow.c

• O soukrom´ych kl´ıˇcovan´ych atributech vl´aknav´ıcena stranˇe 221.

• Kaˇzd´evl´aknom´ajeˇstˇevlastn´ısign´alovou masku, k tomu se tak´edostaneme, viz strana 224.

216 Ukonˇcen´ıvl´akna

void pthread exit(void *val ptr ); • ukonˇc´ıvolaj´ıc´ıvl´akno,je to obdoba exit pro proces int pthread join(pthread t thr, void **val ptr ); • poˇck´ana ukonˇcen´ıvl´akna thr a ve val ptr vr´at´ıhodnotu ukazatele z pthread exit nebo n´avratovou hodnotu vl´aknov´e funkce. Pokud vl´aknoskonˇcilodˇr´ıve, funkce hned vrac´ı pˇr´ısluˇsnˇenastaven´e val ptr. • obdoba ˇcek´an´ına synovsk´yproces pomoc´ı wait int pthread detach(pthread t thr ); • nastav´ıokamˇzit´euvolnˇen´ıpamˇetipo ukonˇcen´ıvl´akna,na vl´aknonelze pouˇz´ıt pthread join.

• Pokud se nepouˇzije pthread exit, vyvol´ase tato funkce pˇriskonˇcen´ıvl´akna implicitnˇe,s hodnotou pouˇzitoupro return • Norma specifikuje, ˇzestav z´asobn´ıkuukonˇcovan´ehovl´aknanen´ıdefinovan´y, a proto by se v pthread exit nemˇelypouˇz´ıvat odkazy na lok´aln´ıpromˇenn´e ukonˇcovan´ehovl´aknapro parametr val ptr

• Pokud nem´ame v ´umyslu po skonˇcen´ıvl´akna volat pthread join, je tˇreba zavolat pthread detach. Jinak po ukonˇcen´emvl´aknu z˚ustanouv pamˇetidata nutn´apro zjiˇstˇen´ıjeho v´ysledku pomoc´ı pthread join. To je podobn´asitu- ace, jako kdyˇzrodiˇcovsk´yproces nepouˇz´ıv´a wait a v syst´emu se hromad´ı zombie. Ve funkci pro takov´evl´aknoje moˇzn´ejednoduˇsepouˇz´ıttoto:

pthread detach(pthread self());

• Jin´amoˇznostjak nastavit, ˇzese na vl´aknanemus´ıˇcekat, je zavolat funkci pthread attr setdetachstate s hodnotou PTHREAD CREATE DETACHED nad strukturou atribut˚ua tu pak pouˇz´ıtve vol´an´ıch pthread create. Pˇr´ıklad: pthreads/set-detachstate.c

• Nastaven´ım NULL do argumentu val ptr syst´emu sdˇelujeme,ˇzen´asn´avra- tov´ahodnota ukonˇcen´ehovl´aknanezaj´ım´a. • Cekatˇ na ukonˇcen´ı vl´aknam˚uˇzelibovoln´ejin´evl´akno,nejen to, kter´eho spustilo.

217 • Doporuˇcujivˇzdykontrolovat n´avratovou hodnotu pthread join, t´ımsi bu- dete jisti, ˇzeˇcek´atespr´avnˇe,pˇripouˇzit´ıˇspatn´ehoID vl´aknafunkce hned vr´at´ı, coˇzv´aˇsprogram nutnˇenemus´ınegativnˇeovlivnit co se t´yk´afunkˇcnosti,ale m˚uˇzetepak narazit na limit poˇctuvl´aken nebo vypl´ytvat pamˇet’. • Na rozd´ılod proces˚u nelze ˇcekat na ukonˇcen´ıkter´ehokoli vl´akna. Je to z toho d˚uvodu, ˇzevl´aknanemaj´ıvztah rodiˇc–potomek, a proto to nebylo povaˇzov´anoza potˇrebn´e.Pro zaj´ımavost, Solaris vl´aknatoto umoˇzn´ı(jako ID vl´aknave funkci thr join se pouˇzije0). Pokud byste tuto funkˇcnost potˇrebovali s POSIXov´ymivl´akny, je jednoduch´enastavit vl´aknajako de- tached, pouˇz´ıtpodm´ınkov´epromˇenn´e, a pˇred´avat potˇrebn´einformace pˇres glob´aln´ıpromˇennoupod ochranou z´amku,kter´yje s podm´ınkovou promˇennou sv´az´an.V´ıceviz strana 229.

• Pˇr´ıklady: pthreads/pthread-join.c , pthreads/pthread-detach-join.c

Inicializace

int pthread once(pthread once t *once control, void (*init routine )(void)); • V parametru once control se pˇred´av´aukazatel na staticky inicializovanou promˇennou pthread once t once control = PTHREAD ONCE INIT; • Prvn´ıvl´akno,kter´ezavol´a pthread once(), provede inicializaˇcn´ıfunkci init routine(). Ostatn´ıvl´aknauˇztuto funkci neprov´adˇej´ı, nav´ıc,pokud inicializaˇcn´ıfunkce jeˇstˇe neskonˇcila,zablokuj´ıse a ˇcekaj´ına jej´ıdokonˇcen´ı. • Lze pouˇz´ıtnapˇr.na dynamickou inicializaci glob´aln´ıch dat v knihovn´ach, jejichˇzk´odm˚uˇzezavolat v´ıcevl´aken souˇcasnˇe, ale je tˇrebazajistit, ˇzeinicializace probˇehne jen jednou.

• V programu samotn´emtuto funkci asi potˇrebovat nebudete. M´ıstopouˇzit´ı pthread once staˇc´ıdanou inicializaˇcn´ıfunkci zavolat pˇredt´ım,neˇzvytvoˇr´ıte vl´akna...

• Nen´ıdefinov´ano,co se m´ast´at,pokud je once control automatick´apromˇen- n´anebo nem´apoˇzadovanou hodnotu.

218 Zruˇsen´ıvl´akna

int pthread cancel(pthread t thread ); • poˇz´ad´ao zruˇsen´ıvl´akna thread. Z´avis´ına nastaven´ı int pthread setcancelstate(int state, int *old ); • nastav´ınov´ystav a vr´at´ıstar´y: – PTHREAD CANCEL ENABLE . . . povoleno zruˇsit – PTHREAD CANCEL DISABLE . . . nelze zruˇsit,ˇz´adostbude ˇcekat na povolen´ı int pthread setcanceltype(int type, int *old ); • PTHREAD CANCEL ASYNCHRONOUS . . . okamˇzit´ezruˇsen´ı • PTHREAD CANCEL DEFERRED . . . ˇz´adostˇcek´ana vstup do urˇcit´ych funkc´ı(napˇr. open(), read(), wait()), nebo na vol´an´ı void pthread testcancel(void);

• Vl´aknaje moˇzn´ezvenku ,,n´asilnˇe”ruˇsit(obdoba ukonˇcen´ıprocesu pomoc´ı sign´alu)bud’ okamˇzitˇe,nebo jen v urˇcit´ych vol´an´ıch (tzv. cancellation points). To znamen´a,ˇzev takov´empˇr´ıpadˇeje moˇzn´evl´aknozruˇsitv ˇcase,kdy je vl´aknovykon´av´adanou funkci. Pokud vl´aknozrovna takovou funkci nevy- kon´av´a,informace o zruˇsen´ıse “doruˇc´ı”bˇehemvykon´an´ıprvn´ıtakov´efunkce od t´edoby.

• Funkce pthread_cancel se podob´azruˇsen´ıprocesu sign´alemposlan´ymvo- l´an´ım kill. • Pˇrizruˇsen´ıvl´aknase zavolaj´ı ´uklidov´ehandlery, viz strana 222. Pokud se rozhodnete ruˇsen´ıvl´aken pouˇz´ıvat, bud’te velmi opatrn´ı. Napˇr´ıklad,pokud budete ruˇsitvl´akno,kter´em´azamknut´ymutex, mus´ıtemutex odemknout v ´uklidov´ych handlerech.

• Funkce pthread_setcancelstate a pthread_setcanceltype jsou obdobou zak´az´an´ıa povolen´ızruˇsen´ıprocesu sign´alempomoc´ımanipulace s maskou blokovan´ych sign´al˚u(sigprocmask).

• Pˇr´ıklad: pthreads/pthread-cancel.c

• Pˇriruˇsen´ıvl´aknam˚uˇzenastat mnoho moˇznost´ı.Solaris m´atˇrebasamostatnou manu´alnovou str´anku cancellation(5), kter´ase tomu vˇenuje. FreeBSD de- finuje cancellation points v manu´alov´estr´ance pthread setcanceltype(3).

219 Pˇr´ıklad:vl´akna

pthread_t id_a, id_b; void *res_a, *res_b; pthread_create(&id_a, NULL, do_a, "a"); pthread_create(&id_b, NULL, do_b, "b");

void *do_a(void *arg) void *do_b(void *arg) { { ...... return arg; return arg; } }

pthread_join(id_a, &res_a); pthread_join(id_b, &res_b);

• Toto je trivi´aln´ıpˇr´ıklad, kdy proces (hlavn´ıvl´akno)vytvoˇr´ıdvˇedalˇs´ıvl´akna a poˇck´ana jejich ukonˇcen´ı.

220 Glob´aln´ıpromˇenn´epro vl´akno

int pthread key create(pthread key t *key, void (*destructor )(void *)); • vytvoˇr´ıkl´ıˇc,kter´ylze asociovat s hodnotou typu (void *). Funkce destructor() se volaj´ıopakovanˇepro vˇsechny kl´ıˇce, jejichˇzhodnota nen´ı NULL, pˇriukonˇcen´ıvl´akna. int pthread key delete(pthread key t key ); • zruˇs´ıkl´ıˇc,nemˇen´ıasociovan´adata. int pthread setspecific(pthread key t key, const void *value ); • pˇriˇrad´ıukazatel value ke kl´ıˇci key. void *pthread getspecific(pthread key t key ); • vr´at´ıhodnotu ukazatele pˇr´ısluˇsn´ehoke kl´ıˇci key.

• Bˇeˇzn´eglob´aln´ıpromˇenn´e(a tak´edynamicky alokovan´adata) jsou spoleˇcn´e pro vˇsechna vl´akna.Kl´ıˇcovan´ehodnoty pˇredstavuj´ızp˚usob,jak vytvoˇritglo- b´aln´ıpromˇenn´ev r´amcivl´aken. Uvˇedomte si rozd´ılproti lok´aln´ıpromˇenn´e definovan´eve vl´aknov´efunkci - takov´apromˇenn´anen´ıvidˇetv dalˇs´ıch vo- lan´ych funkc´ıch ve stejn´emvl´aknˇe.Vyuˇzitelnostsoukrom´ych atribut˚uvl´aken se m˚uˇzezd´atmal´a,ale obˇcasse to velmi dobˇrehod´ı.J´ato jednou pouˇzilv existuj´ıc´ımk´odu,kde jsem potˇreboval nahradit pr´acis glob´aln´ımspojov´ym seznamem na lok´aln´ıseznamy specifick´epro kaˇzd´evl´akno.Nejjednoduˇsˇs´ı,tj. nejm´enˇezmˇenv existuj´ıc´ımk´odubylo pˇrev´estpr´acis glob´aln´ıpromˇennouna pr´acise soukrom´ymatributem vl´akna. • Pˇrivytvoˇren´ıkl´ıˇceje s n´ımasociov´anahodnota NULL. Ukazatel na destruktor funkci nen´ıpovinn´y,pokud nen´ıpotˇreba,pouˇzijte NULL. • Pˇriukonˇcen´ınebo zruˇsen´ıvl´aknase volaj´ıdestruktory (v nespecifikovan´em poˇrad´ı) pro vˇsechny kl´ıˇce s hodnotou r˚uznouod NULL. Aktu´aln´ı hodnota je destruktoru pˇred´anav parametru. Jestliˇzepo skonˇcen´ıvˇsech destruktor˚u zb´yvaj´ıkl´ıˇces hodnotou r˚uznouod NULL, znovu se volaj´ıdestruktory. Imple- mentace m˚uˇze(ale nemus´ı)zastavit vol´an´ıdestruktor˚upo PTHREAD DESTRUC- TOR ITERATIONS iterac´ıch. Destruktor by tedy mˇelnastavit hodnotu na NULL, jinak hroz´ınekoneˇcn´ycyklus. • Destruktor si mus´ıs´amzjistit kl´ıˇcpoloˇzky, ke kter´epatˇr´ı,a zruˇsithodnotu vol´an´ım pthread setspecific(key, NULL). • SUSv3 tento nesmysln´ypoˇzadavek odstraˇnuje,protoˇzedefinuje, ˇzepˇredvstu- pem do destruktoru je hodnota automaticky nastaven´ana NULL; destruktor se n´aslednˇevyvol´as pˇredchoz´ıhodnotou kl´ıˇce.

221 Uklid´ pˇriukonˇcen´ı/zruˇsen´ıvl´akna

• vl´aknom´az´asobn´ık´uklidov´ych handler˚u,kter´ese volaj´ıpˇri ukonˇcen´ınebo zruˇsen´ıvl´aknafunkcemi pthread exit a pthread cancel (ale ne pˇri return). Handlery se spouˇst´ıv opaˇcn´empoˇrad´ıneˇzbyly vkl´ad´any do z´asobn´ıku. • po proveden´ıhandler˚use volaj´ıdestruktory priv´atn´ıch kl´ıˇcovan´ych dat vl´akna(poˇrad´ınen´ıspecifikovan´e)

void pthread cleanup push(void (*routine )(void *), void *arg ); • vloˇz´ıhandler do z´asobn´ıku. void pthread cleanup pop(int execute ); • vyjme naposledy vloˇzen´yhandler ze z´asobn´ıku.Provede ho, pokud je execute nenulov´e.

• Handlery se volaj´ıjako routine(arg). • Tyto handlery se daj´ıpouˇz´ıvat napˇr.na ´uklidlok´aln´ıch dat funkc´ı(obdoba vol´an´ıdestruktor˚upro automatick´epromˇenn´ev C++).

222 fork() a vl´akna (POSIX)

• je nutn´edefinovat s´emantiku vol´an´ı fork v aplikac´ıch pouˇz´ıvaj´ıc´ıch vl´akna.Norma definuje, ˇze: – nov´yproces obsahuje pˇresnoukopii volaj´ıc´ıhovl´akna, vˇcetnˇepˇr´ıpadn´ych stav˚umutex˚ua jin´ych zdroj˚u – ostatn´ıvl´aknav synovsk´emprocesu neexistuj´ı – pokud takov´avl´aknamˇelanaalokovanou pamˇet’, z˚ustane tato pamˇet’ naalokovan´a(= ztracen´a) – obdobnˇeto plat´ıpro zamˇcen´ymutex jiˇzneexistuj´ıc´ıho vl´akna • vytvoˇren´ınov´ehoprocesu z multivl´aknov´eaplikace m´asmysl pro n´asledn´evol´an´ı exec (tj. vˇcetnˇevol´an´ı popen, system apod.)

• Pokud mˇelojiˇzneexistuj´ıc´ı vl´aknozamˇcen´ymutex, tak je pˇr´ıstup k pˇr´ı- sluˇsn´ymsd´ılen´ymdat˚umztracen, protoˇzezamˇcen´ymutex m˚uˇzeodemknout pouze to vl´akno,kter´eho zamknulo. Zde ale trochu pˇredb´ıh´am,mutexy jsou pˇredstaven´eaˇzna stranˇe 226. • Ostatn´ıvl´aknav nov´emprocesu pˇrestanouexistovat, nevolaj´ıse ˇz´adn´erutiny jako pˇrivol´an´ı pthread exit, pthread cancel nebo destruktory kl´ıˇcovan´ych dat. • Pozor na to, ˇzechov´an´ı fork tak´ez´avis´ına pouˇzit´eknihovnˇea verzi syst´emu, napˇr´ıkladna Solarisu pˇredverz´ı10 znamenalo fork v knihovnˇe libthread (jin´aknihovna neˇz libpthread) to sam´eco forkall.

• Pˇr´ıklady: pthreads/fork.c , pthreads/fork-not-in-main.c , pthreads/forkall.c

• Pomoc´ıfunkce pthread atfork je moˇzn´enastavit handlery kter´ese auto- maticky vykonaj´ıpˇredpouˇzit´ım fork v rodiˇcia po n´avratuz fork v rodiˇci a synovsk´emprocesu. Toto vol´an´ıse velmi hod´ıpro vˇsechny multithreadov´e programy kter´evolaj´ı fork a nepouˇz´ıvaj´ıho pouze jako jednoduch´ywrapper pro exec. Po fork se totiˇzv synovsk´emprocesu nach´azej´ıvˇsechny promˇenn´e ve stejn´emstavu jako byly v rodiˇcive chv´ılikdy se zavolal fork a tedy po- kud mˇelonˇejak´ejin´evl´akno(neˇzkter´ezavolalo fork) napˇr.zamˇcen´ymutex (zamyk´an´ıpomoc´ımutex˚uviz strana 226) tak bude tento mutex zamˇcen´yi v synovsk´emprocesu. Pokud se pak vl´aknoze synovsk´ehoprocesu tento mutex pokus´ızamknout, dojde k deadlocku. Pokud se v pre-fork handleru provede zamˇcen´ıvˇsech mutex˚ua v obou (rodiˇci syn) post-fork handler˚uodemˇcen´ı vˇsech mutex˚u,tato situace nenastane. Tento mechanismus funguje d´ıkytomu,

223 ˇze pre-fork handler se zavol´ave vl´aknu, kter´ezavolalo fork, jeˇstˇepˇredt´ımneˇz se provede samotn´yfork syscall; ostatn´ıvl´aknamezit´ımd´albˇeˇz´ıa mohou tedy uvolnit mutexy (jednoduˇsetak ˇzekaˇzd´evl´aknov rozumnˇenapsan´em programu ˇcasemopust´ıkritickou sekci), na kter´ese ˇcek´av handleru. Toto samozˇrejmˇepˇredpokl´ad´a,ˇzezamyk´an´ıa odemyk´an´ıv handlerech dodrˇzuje zamykac´ıpravidla (”protokol”) stanoven´ypro cel´yprogram a nedojde tedy k deadlocku. pthreads/atfork.c V´ıcenapˇr.v [Butenhof].

Sign´alya vl´akna

• sign´alymohou b´ytgenerov´any pro proces (vol´an´ım kill), nebo pro vl´akno(chybov´eud´alosti,vol´an´ı pthread kill). • nastaven´ıobsluhy sign´al˚uje stejn´epro vˇsechna vl´aknaprocesu, ale masku blokovan´ych sign´al˚um´akaˇzd´evl´aknovlastn´ı, nastavuje se funkc´ı

int pthread sigmask(int how, const sigset t *set, sigset t *oset ); • sign´alurˇcen´ypro proces oˇsetˇr´ıvˇzdypr´avˇejedno vl´akno,kter´e nem´atento sign´alzablokovan´y. • lze vyhradit jedno vl´aknopro synchronn´ıpˇr´ıjemsign´al˚u pomoc´ıvol´an´ı sigwait. Ve vˇsech vl´aknech se sign´alyzablokuj´ı.

• Jestliˇzeje pro sign´alnastaveno ukonˇcen´ıprocesu, skonˇc´ıcel´yproces, nejen jedno vl´akno. • Vytvoˇren´evl´aknodˇed´ınastaven´ısign´alov´emasky od vl´akna, kter´eho vy- tvoˇrilo • Analogicky k pouˇzit´ı sigwait s procesy (strana 159) – zablokujte pˇr´ısluˇsn´e sign´alyve vˇsech vl´aknech, vˇcetnˇevl´akna,ve kter´emchcete zpracov´av´avat sign´alypomoc´ı sigwait. Tento zp˚usobzpracov´an´ısign´al˚ub´yv´aˇcasto jedin´yopravdu doporuˇcovan´ypro vl´akna, a nav´ıcje i nejsn´azeimple- mentovateln´y.Jak vypl´yv´az pˇredchoz´ıpozn´amky, staˇc´ızamaskovat sign´aly pouze jednou, a to v hlavn´ımvl´aknˇe,protoˇzemaska se pak podˇed´ıpˇrikaˇzd´em vol´an´ı pthread create. • V prostˇred´ıvl´aken nepouˇz´ıvejte sigprocmask (strana 157), protoˇzechov´an´ı tohoto vol´an´ınen´ıv takov´emprostˇred´ınormou specifikov´ano.M˚uˇzeto fun- govat, a tak´enemus´ı.

• Pˇr´ıklad: pthreads/sigwait.c .

224 • Pozor na to, ˇzebyste nemˇelitento zp˚usobobsluhy sign´al˚upouˇz´ıvat pro sign´alysynchronn´ıjako jsou SIGSEGV, SIGILL, apod. Tyto sign´alyjsou ge- nerovan´epˇr´ımopro vl´akno,takˇzepokud je zablokujete, vl´aknourˇcen´epro synchronn´ıpˇr´ıjem sign´al˚uje nemus´ı“vidˇet”,jedinˇepokud by ten sign´alzp˚u- sobilo samo, samozˇrejmˇe.Dalˇs´ı vˇecale je, ˇzespecifikac´ı nen´ı definov´ano, zda blokov´an´ıtakov´ych sign´al˚utyto sign´alyskuteˇcnˇezablokuje, jak jiˇzbylo zm´ınˇenona stranˇe 150. Nˇekter´esyst´emy tyto sign´alynorm´alnˇedoruˇc´ı,ˇc´ımˇz proces ukonˇc´ı,viz pˇresn´eznˇen´ı:

If any of the SIGFPE, SIGILL, SIGSEGV, or SIGBUS signals are generated while they are blocked, the result is undefined, unless the signal was generated by the kill() function, the sigqueue() function, or the raise() function.

Pˇr´ıklad: pthreads/sigwait-with-sync-signals.c . Tento pˇr´ıkladukazuje, ˇzena Solarisu 10, Solarisu 11, FreeBSD 7.2 a Linux distribuci, kter´ase hl´as´ı jako “Gentoo Base System release 1.12.13”, je sign´al SIGSEGV doruˇcena pro- ces zabit bez ohledu na to, zda je maskov´an.Naˇseljsem ale i syst´em,kter´y po zamaskov´an´ısign´alnedoruˇc´ı– FreeBSD 6.0. Synchronn´ısign´alyby ale mˇelob´ytvˇzdymoˇzn´ezachytit (pˇredzavol´an´ım exit), viz strana 150, kde je i pˇr´ıklad.

Synchronizace vl´aken obecnˇe

• vˇetˇsinaprogram˚upouˇz´ıvaj´ıc´ıch vl´aknamezi nimi sd´ıl´ıdata • nebo vyˇzaduje,aby r˚uzn´eakce byly prov´adˇeny v jist´empoˇrad´ı • . . . toto vˇsepotˇrebuje synchronizovat aktivitu bˇeˇz´ıc´ıch vl´aken • jak bylo zm´ınˇenou implementace vl´aken, u proces˚uje pro sd´ılen´ıdat nutn´evynaloˇzitjist´e´usil´ı,u vl´aken naopak mus´ıme investovat do toho, abychom pˇrirozen´esd´ılen´ıdat uhl´ıdali • my se vzhledem k vl´akn˚umbudeme zab´yvat: – mutexy – podm´ınkov´ymipromˇenn´ymi – read-write z´amky

• pro pˇripomenut´ı,synchronizac´ıproces˚ujsme se jiˇzzab´yvali na stran´ach 161 aˇz 178. • pomoc´ımutex˚ua podm´ınkov´ych promˇenn´ych je moˇzn´epostavit jak´ykoli jin´y synchronizaˇcn´ımodel.

225 • na tom jak´ymzp˚usobem budou fungovat synchronizaˇcn´ıprimitiva se velkou ˇc´ast´ı pod´ıl´ı scheduler, kter´ynapˇr.rozhoduje kter´ez vl´aken ˇcekaj´ıc´ıch na odemˇcen´ıbude po odemˇcen´ıprobuzeno. S t´ımsouvis´ıklasick´eprobl´emy, napˇr. thundering horde (na odemˇcen´ıˇcek´avelk´emnoˇzstv´ıvl´aken) nebo priority inversion (vl´akno,kter´edrˇz´ı z´amek,m´amenˇs´ı prioritu neˇzvl´akno,kter´e ˇcek´ana tento z´amek).

Synchronizace vl´aken: mutexy (1)

• nejjednoduˇsˇs´ızp˚usobzajiˇstˇen´ısynchronizovan´ehopˇr´ıstupuke sd´ılen´ymdat˚ummezi vl´akny je pouˇzit´ım mutexu • inicializace staticky definovan´ehomutexu: pthread mutex t mutex = PTHREAD MUTEX INITIALIZER; • inicializace dynamicky alokovan´ehomutexu mx s atributy attr (nastavuj´ıse pomoc´ı pthread mutexattr ...; a je-li m´ısto attr pouˇzit NULL, vezmou se defaultn´ıatributy)

int pthread mutex init(pthread mutex t *mx, const pthread mutexattr t *attr ); • po skonˇcen´ıpouˇz´ıv´an´ımutexu je moˇzn´eho zruˇsit: int pthread mutex destroy(pthread mutex t *mx );

• Mutex = mutual exclusion (vz´ajemn´evylouˇcen´ı) • Je to speci´aln´ıforma Dijkstrov´ych semafor˚u– rozd´ılmezi mutexy a bin´arn´ımi semafory je ten, ˇze mutex m´amajitele a zamˇcen´ymutex mus´ıode- mknout pouze to vl´akno,kter´eho zamknulo. To u semafor˚uneplat´ı. Pozor na to, ˇzeabyste zjistili, ˇzenapˇr´ıkladzkouˇs´ıteodemknout mutex, kter´y dan´evl´aknonezamknulo, je nutn´ejednak testovat n´avratovou hodnotu vol´an´ı pthread mutex lock, a tak´eje nutn´eovˇeˇrit,ˇzem´atenastavenou kontrolu za- myk´an´ı;viz d´ale. • Mutexy jsou urˇcen´epouze ke kr´atkodob´emu drˇzen´ıa mˇelyby fungovat rychle. Slouˇz´ıpro implementaci kritick´ych sekc´ı(definice je na stranˇe 163), podobnˇe jako lock-soubory nebo semafory (pouˇzit´ejako z´amky). • Kontrola zamyk´an´ıu mutex˚u– defaultnˇeje typ mutexu PTHREAD MUTEX DEF- AULT. V tomto nastaven´ınejsou normou definov´any v´ysledkyzamknut´ıjiˇz zamknut´ehomutexu, odemknut´ımutexu zamknut´ehojin´ymvl´aknemani ode- mknut´ıodemknut´ehomutexu. Implementace si namapuj´ıtoto makro na nor- mou definovan´e PTHREAD MUTEX NORMAL nebo PTHREAD MUTEX ERRORCHECK. M˚uˇzese v´amproto v z´avislostina konkr´etn´ıimplementaci st´at,ˇzepokud

226 v defaultn´ıkonfiguraci zamknete jiˇzjednou zamknut´ymutex, nastane de- adlock (normal), a nebo tak´ene (errorcheck). V tom druh´empˇr´ıpadˇedosta- nete n´avratovou hodnotu o chybˇea pokud ji netestujete, budete se mylnˇe domn´ıvat, ˇzejste mutex zamknuli. U normal nen´ı v´ysledekzbyl´ych dvou situac´ıdefinov´an,u errorcheck se v´amvr´at´ıchyba. “Nedefinov´ano”u nor- mal znamen´a,ˇzevl´aknoodemykaj´ıc´ı mutex, kter´ynezamknulo, ho klidnˇe m˚uˇzeodemknout, nebo tak´ene – vˇsez´avis´ına konkr´etn´ıimplementaci. “Ne- definov´ano”ale tak´eznamen´a,ˇzeskuteˇcn´yv´ysledektakov´ychto situac´ıby v´asnemˇel zaj´ımat, protoˇzebyste se jim vˇzdymˇelivyhnout. V´ıce infor- mac´ı viz norma nebo manu´alov´astr´anka k pthread mutexattr settype. Mnˇeosobnˇepˇrijdetestov´an´ımutexov´ych funkc´ıjako nadbyteˇcn´ea trochu znepˇrehledˇnuj´ıc´ık´od,ale m˚uˇzeb´ytdobr´yn´apadje pouˇz´ıvat pˇriv´yvoji k´odu, a pˇredodevzd´an´ım fin´aln´ı verze pak testy odstranit. Solaris a Linux de- faultnˇepouˇz´ıvaj´ı nastaven´ı normal, FreeBSD pouˇz´ıv´aerrorcheck. Pˇr´ıklad: mutexes/not-my-lock.c .

• dalˇs´ıtyp je PTHREAD MUTEX RECURSIVE kter´edrˇz´ıpoˇcetzamˇcen´ıdan´ymthrea- dem. Ostatn´ıthready dostanou pˇr´ıstupjedinˇetehdy kdyˇzpoˇcetdos´ahne0. Tento typ mutexu nelze sd´ıletmezi procesy. • K ˇcemu jsou dobr´erekurzivn´ımutexy ? Napˇr.m´ame-liknihovn´ıfunkci A:foo(), kter´az´ısk´amutex a zavol´aB:bar() kter´aale m˚uˇzezavolat A:bar(), kter´ase pokus´ız´ıskat ten sam´ymutex. Bez rekurzivn´ıch z´amk˚uby doˇslok deadlocku. S rekurzivn´ımimutexy je to ok pokud tyto vol´an´ıprov´ad´ıten sam´ythread (jin´ythread by se zablokoval), pokud si tedy A:foo() a A:bar() jsou vˇedomy, ˇzeten sam´ythread uˇzm˚uˇzeb´ytv kritick´esekci. • Chov´an´ıv jednotliv´ych pˇr´ıpadech podle typu mutex˚ushrnuje tabulka:

NORMAL ERRORCHECK RECURSIVE detekuje deadlock N Y N/A v´ıcen´asobn´ezamyk´an´ı deadlock error success odemˇcen´ıjin´ymvl´aknem undefined error error odemyk´an´ıodemˇcen´eho undefined error error lze sd´ıletmezi procesy Y Y N • Inicializace statick´ehomutexu pomoc´ızm´ınˇen´ehomakra nastav´ıpro mutex jeho defaultn´ıatributy. Je moˇzn´epouˇz´ıtinicializaˇcn´ıfunkci i pro staticky alokovan´emutexy. Pokud je mutex alokov´andynamicky, je vˇzdynutn´epouˇz´ıt pthread mutex init funkci, at’ jiˇzbudeme pouˇz´ıvat defaultn´ıatributy nebo ne.

• Dynamick´emutexy m˚uˇzeme potˇrebovat napˇr´ıkladv situaci, kdy dynamicky alokujeme datovou strukturu, jej´ıˇzsouˇc´ast´ıje i mutex, kter´ysd´ılen´adata struktury chr´an´ı.I zde, pˇredzavol´an´ımfunkce free na datovou strukturu, je potˇrebapouˇz´ıtvol´an´ıpro zruˇsen´ımutexu, protoˇzemutex s´amm˚uˇzem´ıt napˇr´ıkladalokovanou nˇejakou pamˇet’. V´ysledekzruˇsen´ızamknut´ehomutexu nen´ınormou definov´an. • Kop´ırovat mutexy nen´ınormou definov´ano– v´ysledektakov´eoperace z´avis´ı na implementaci. Je moˇzn´esamozˇrejmˇezkop´ırovat ukazatel na mutex a s t´ımto ukazatelem pak d´alepracovat. • Zruˇsen´ımutexu znamen´ajeho deinicializaci.

227 Mutexy (2)

• pro zamˇcen´ıa odemˇcen´ımutexu pouˇzijemevol´an´ı:

int pthread mutex lock(pthread mutex t *mx ); a int pthread mutex unlock(pthread mutex t *mx ); • pokud je mutex jiˇzzamˇcen´y,pokus o zamknut´ıvy´ust´ıv zablokov´an´ıvl´akna.Je moˇzn´epouˇz´ıti vol´an´ı:

int pthread mutex trylock(pthread mutex t *mx ); ... kter´ese pokus´ızamknout mutex, a pokud to nelze prov´est, skonˇc´ıs chybou

• zamknout mutex, pokud ho dan´evl´aknojiˇzzamˇcen´em´a,nen´ı korektn´ı. Nˇekdym˚uˇzedoj´ıti k self dead-locku, viz pˇredchoz´ıstrana. Pokud potˇrebujete odemknout mutex, kter´yzamknulo jin´evl´akno,pouˇzijtem´ıstotoho bin´arn´ı semafor; opˇetviz pˇredchoz´ıstrana. • pˇrivytv´aˇren´ıaplikace, kde je efektivita kl´ıˇcov´ymfaktorem, je nutn´erozmys- let, jak, kde a kolik mutex˚upouˇz´ıvat. Z knihovny, kter´anebyla napsan´apro pouˇzit´ıv aplikac´ıch pouˇz´ıvaj´ıc´ıvl´akna,je moˇzn´eudˇelatthread-safe (viz tak´e strana 239) knihovnu tak, ˇze pˇredzavol´an´ımjak´ekoli funkce knihovny za- mknu jeden, tzv. “giant” mutex a po skonˇcen´ı funkce ho odemknu. M´am tedy pouze jeden mutex, ale vl´aknapouˇz´ıvaj´ıc´ıtuto knihovnu ˇcastosp´ıpˇri ˇcek´an´ına pˇr´ıstupdo knihovny. Na druhou stranu, pokud zamyk´ampˇr´ıstup ke konkr´etn´ım, mal´ymsekc´ım, mohu potˇrebovat mnoho mutex˚ua znaˇcn´e mnoˇzstv´ıˇcasutak mohu str´avitve funkc´ıch, kter´emutexy implementuj´ı.Je proto vhodn´epodle situace zvolit rozumn´ykompromis. Tak´enezapomeˇnte, ˇzeje moˇzn´eexplicitnˇenastavit, zda chcete error checking u mutex˚unebo ne. M˚uˇzeb´ytdobr´eˇreˇsen´ıkontrolu zamyk´an´ı/odemyk´an´ıvypnout tehdy, kdyˇz uˇzm´atevˇseotestovan´ea vˇeˇr´ıte,ˇzeerror checking k´odd´alenepotˇrebujete.

• pˇr´ıklady: mutexes/race.c a mutexes/race-fixed.c • mutexy je moˇzn´enastavit i pro fungovan´ımezi vl´akny r˚uzn´ych proces˚u. Fun- guje to tak, ˇzefunkce implementuj´ıc´ımutexy vyuˇzij´ısd´ılenoupamˇet’, jej´ıˇz odkaz se nastav´ıjako jeden z atribut˚umutexu. V´ıceviz manu´alov´astr´anka pro pthread mutexattr setpshared.

228 Podm´ınkov´epromˇenn´e(1)

• mutexy slouˇz´ıpro synchronizaci pˇr´ıstupuke sd´ılen´ymdat˚um • podm´ınkov´epromˇenn´epak k pˇred´an´ıinformac´ıo tˇechto sd´ılen´ych datech – napˇr´ıkladˇze se hodnota dat zmˇenila • . . . a umoˇzn´ıtak vl´aknapodle potˇreby usp´avat a probouzet • z toho plyne, ˇze kaˇzd´apodm´ınkov´apromˇenn´aje vˇzdy asociov´anas pr´avˇejedn´ımmutexem • jeden mutex ale m˚uˇzeb´ytasociov´ans v´ıcepodm´ınkov´ymi promˇenn´ymi • spoleˇcnˇepomoc´ımutex˚ua podm´ınkov´ych promˇenn´ych je moˇzn´evytv´aˇretdalˇs´ısynchronizaˇcn´ıprimitiva – semafory, bari´ery, . . .

• jin´ymislovy – podm´ınkov´epromˇenn´ese pouˇz´ıvaj´ı v situaci, kdy vl´akno potˇrebujeotestovat stav sd´ılen´ych dat (napˇr.poˇcetzpr´avve frontˇe),a dob- rovolnˇese uspat, kdyˇzhledan´ehostavu nebylo dosaˇzeno.Sp´ıc´ıvl´aknoje pak probuzeno jin´ymvl´aknem,kter´ezmˇenilostav dat tak, ˇze nastala situace, na kterou prvn´ıvl´aknoˇcek´a(tˇrebavloˇzen´ımprvku do fronty). Druh´evl´akno vzbud´ıprvn´ıvl´akno zavol´an´ımk tomu urˇcen´efunkce. Pokud ˇz´adn´evl´aknov dan´echv´ılinesp´ı,probouzec´ıfunkce nem´aˇz´adn´yefekt – nic se nikde neuloˇz´ı, prostˇejako by se to nikdy nestalo. • nen´ıto tak, ˇzepˇrideklaraci podm´ınkov´epromˇenn´e,coˇzje pro program´atora zcela transparentn´ıtyp, s n´ıasociujete podm´ınkunapˇr.“n je vˇetˇs´ıneˇz7 ”. Podm´ınkovou promˇennoutotiˇzm˚uˇzetepˇrirovnat k praporu nˇejak´ebarvy, a pokud jej zvednete, znamen´ato, ˇzeta vl´akna,kter´aˇcekaj´ıaˇztouto vlajkou nˇekdozam´av´anad hlavou, jsou o t´etosituaci informov´ana(= vzbuzena) a mohou se podle toho zaˇr´ıdit.Nˇekter´avl´aknatak mohou ˇcekat na to, aˇz n bude vˇetˇs´ıneˇz7, jin´amohou ˇcekat pouze na to, aˇzse n jakkoli zmˇen´ı.Je pouze na program´atorovi, zda pro kaˇzdoukonkr´etn´ısituaci pouˇzijejednu podm´ınkovou promˇennou,nebo jednu pro vˇsechny situace dohromady. Pro druhou situaci plat´ı,ˇzevl´aknaˇcekaj´ıc´ına n == 7 pak mus´ıvˇzdy n otestovat, protoˇzev´ı,ˇze je vzbuzeno pˇrikazd´ezmˇenˇeˇc´ıtaˇce n. Pokud nen´ıˇc´ıtaˇcroven sedmi, znovu se dobrovolnˇeusp´ı.Jak je vˇsakuvedeno d´ale, test je nutn´epo probu- zen´ı prov´estvˇzdy, i kdyˇzpro nˇejpouˇz´ıv´atesamostatnou podm´ınkovou promˇennou– m˚uˇzese st´at,ˇzesyst´emz r˚uzn´ych implementaˇcn´ıch d˚uvod˚u vzbud´ıvl´aknouspan´enad podm´ınkovou promˇennou,aniˇzby to zp˚usobilo jin´evl´aknoa tedy aniˇzby stav na kter´yvl´aknoˇcek´aopravdu nastal.

229 Podm´ınkov´epromˇenn´e(2)

int pthread cond init(pthread cond t *cond, const pthread condattr t *attr ); • Inicializuje podm´ınkovou promˇennou cond s atributy attr (nastavuj´ıje funkce pthread condattr ...()), NULL = default. int pthread cond destroy(pthread cond t *cond ); • zruˇs´ıpodm´ınkovou promˇennou.

int pthread cond wait(pthread cond t *cond, pthread mutex t *mutex ); • ˇcek´ana podm´ınkov´epromˇenn´edokud jin´evl´aknonezavol´a pthread cond signal() nebo pthread cond broadcast().

• je nutn´e,aby po t´e,co vl´aknozamkne mutex a dˇr´ıve, neˇzvl´aknozavol´a pthread cond wait, otestovat podm´ınku. Pokud tuhle operaci vl´aknone- provede, mohlo by se uspat na neurˇcitoudobu, protoˇzehl´aˇska o splnˇen´ı podm´ınkyod jin´eho vl´aknaby proˇsla“bez povˇsimnut´ı”.Jinak ˇreˇceno, nesm´ım se uspat pˇriˇcek´an´ına situaci, kter´auˇzmezit´ımnastala. Nefunguje to jako sign´aly, kter´epro v´assyst´emdrˇz´ı,pokud je m´atenapˇr´ıkladzablokovan´e.Co je d˚uleˇzit´eje to, ˇzeten test prov´ad´ıtepod ochranou mutexu, tedy si opravdu m˚uˇzeteb´ytjist´ıdan´ymstavem vˇec´ıpˇrizavol´an´ı pthread cond wait. • to, ˇzepodm´ınkov´epromˇenn´eopravdu funguj´ıje zp˚usobeno t´ım,ˇzepˇrivstupu do kritick´esekce vl´aknozamkne mutex a funkce pthread cond wait pˇred usp´an´ımvl´aknamutex odemkne. Pˇredn´avratemz t´etofunkce se pak mutex opˇetzamkne. M˚uˇzese tedy st´at,ˇzevl´aknoje probuzeno z ˇcek´an´ı nad podm´ınkovou promˇennou,ale nˇejak´yˇcasse pak jeˇstˇeusp´ıpˇripokusu o zamknut´ı mutexu. Nehledejte v tom nic sloˇzit´eho,jde pouze o klasick´e vz´ajemn´evylouˇcen´ıproces˚unad kritickou sekc´ı.

230 Podm´ınkov´epromˇenn´e(3)

int pthread cond signal(pthread cond t *cond ); • probud´ıjeden proces ˇcekaj´ıc´ına podm´ınkov´epromˇenn´e cond. int pthread cond broadcast(pthread cond t *cond ); • probud´ıvˇsechny procesy ˇcekaj´ıc´ına podm´ınkov´epromˇenn´e cond. int pthread cond timedwait(pthread cond t *cond, pthread mutex t *mutex, const struct timespec *atime ); • ˇcek´ana pthread cond signal() nebo pthread cond broadcast(), ale maxim´alnˇedo doby neˇz syst´emov´yˇcasdos´ahnehodnoty dan´e atime.

• jak jiˇzbylo ˇreˇceno,jedna podm´ınkov´apromˇenn´am˚uˇzeb´ytpouˇzitapro hl´a- ˇsen´ınˇekolika rozd´ıln´ych situac´ınajednou – napˇr´ıkladpˇrivloˇzen´ıprvku do fronty i pˇrijeho vyjmut´ı.Z toho d˚uvodu je nutn´epo probuzen´ıotestovat podm´ınku, na kterou se ˇcek´a.Dalˇs´ı vˇec,kter´az toho vych´az´ı je ta, ˇzev takov´empˇr´ıpadˇemus´ıtepouˇz´ıtbroadcast. Staˇc´ısi pˇredstavit n´asleduj´ıc´ısi- tuaci – ˇcek´atena podm´ınku “zmˇenil se stav fronty”, na kter´eˇcekaj´ıˇcten´aˇrii zapisovatel´e(pˇredpokl´adejme,ˇzejednu frontu pouˇz´ıv´av´ıceˇcten´aˇr˚ui v´ıceza- pisovatel˚u).Pokud po vloˇzen´ızpr´avypouze vypust´ıtejednu signalizaci, tak se m˚uˇzest´at,ˇzetato signalizace probud´ıjin´ehozapisovatele, kter´yale sa- mozˇrejmˇeˇcek´ana situaci, kdy ˇcten´aˇrz fronty zpr´avuodebere. T´ımse stane, ˇzeve frontˇez˚ustanezpr´ava, kter´am˚uˇzeb´ytvytlaˇcenaaˇzdalˇs´ısignalizac´ı.

• vl´aknom˚uˇzeb´ytprobuzeno jin´ymvl´aknemi v pˇr´ıpadˇe,ˇzeje podm´ınkov´a promˇenn´asv´az´anapouze s jednou konkr´etn´ıud´alost´ı,kter´avˇsakpo probu- zen´ıvl´aknajiˇzneplat´ı.Pˇredstavte si, ˇze tˇesnˇepo t´e,kdy jin´evl´aknozahl´as´ı splnˇen´ıpodm´ınky, m˚uˇzedalˇs´ıvl´aknozamknout mutex a nˇejakou akc´ı,napˇr. vyjmut´ımprvku z fronty, zruˇsitplatnost podm´ınky “ve frontˇeje zpr´ava”. To vl´akno,kter´eje probuzeno, tak najde frontu pr´azdnou.Dalˇs´ıd˚uvod pro to, ˇzepodm´ınkov´epromˇenn´eje nutn´e vˇzdy testovat v cyklu. • v ˇr´ıdk´ych pˇr´ıpadech je moˇzn´e,ˇzese vl´aknoprobud´ıa podm´ınka nen´ıplatn´a i d´ıkykonkr´etn´ıimplementaci. Z toho opˇetvypl´yv´anutnost pouˇzit´ıcyklu.

• v parametru abstime funkce pthread cond timedwait se pˇred´av´aabsolutn´ı ˇcas,tj. timeout vyprˇs´ı,kdyˇzsyst´emov´yˇcasdos´ahnehodnoty vˇetˇs´ınebo rovn´e abstime. Pro absolutn´ıˇcasbylo rozhodnuto proto, aby program´atornemusel

231 pˇripˇr´ıpadn´ych probuzen´ıch, kdy n´aslednˇezjist´ı,ˇzedan´apodm´ınka neplat´ı, pˇrepoˇc´ıt´avat ˇcasov´yrozd´ıl.

Pouˇzit´ıpodm´ınkov´ych promˇenn´ych

pthread cond t cond; pthread mutex t mutex; ... pthread mutex lock(&mutex); while (!podminka(data)) pthread cond wait(&cond, &mutex); process data(data, ...); pthread mutex unlock(&mutex); ... pthread mutex lock(&mutex); produce data(data, ...); pthread cond signal(&cond); pthread mutex unlock(&mutex);

• Prvn´ıkus k´oduˇcek´ana zmˇenu podm´ınky. Pokud k n´ıdojde, data zmˇenila a tedy mohou b´ytzpracov´ana.Druh´ykus k´odu(spuˇstˇen´yv jin´emvl´aknˇe) data pˇripravuje ke zpracov´an´ı.Jakmile jsou pˇripravena, zasignalizuje konzu- mentovi. • pro zopakov´an´ı– ke kaˇzd´epodm´ınkov´epromˇenn´eje potˇrebam´ıtjeˇstˇemutex. • funkce pthread cond wait atomicky odemkne mutex a usp´ıvl´akno.Kdyˇzje vl´aknoprobuzeno, nejprve se znovu zamkne mutex (tj. toto zamknut´ıse pro- vede v r´amcipˇr´ısluˇsn´eimplementace podm´ınkov´ych promˇenn´ych!) a teprve pak se vol´an´ı pthread cond wait vr´at´ı. • kdyˇzsignalizujeme, ˇzese nˇecozmˇenilo,neznamen´ato jeˇstˇe,ˇzepo zmˇenˇebude platit podm´ınka. Nav´ıc,jak bylo nˇekolikr´atzd˚uraznˇeno, pthread cond wait m˚uˇzevr´atit,i kdyˇzˇz´adn´ejin´evl´aknonezavolalo pthread cond signal ani pthread cond broadcast. Dalˇs´ıd˚uvod proˇcje potˇrebaznovu otestovat pod- m´ınkua pˇr´ıpadnˇeobnovit ˇcek´an´ı. • Odemknut´ız´amkun´asledujev pˇr´ıkladuna slajdu aˇzpo signalizaci podm´ınky, ale nen´ıto nutn´e.M˚uˇzetesignalizovat aˇzpo odemknut´ıa v takov´empˇr´ıpadˇe to m˚uˇzeb´ytv z´avislostina konkr´etn´ımsyst´emu i efektivnˇejˇs´ı,protoˇzepro- buzen´evl´aknose hned neusp´ına z´amku,kter´yjinak jeˇstˇedrˇz´ıte,pokud sig- nalizujete v r´amcikritick´esekce.

• pˇr´ıklad: cond-variables/queue-simulation.c

232 Read-write z´amky(1)

int pthread rwlock init(pthread rwlock t *l, const pthread rwlockattr t *attr ); • vytvoˇr´ız´amek s atributy podle attr (nastavuj´ıse funkcemi pthread rwlockattr ...(), NULL = default) int pthread rwlock destroy(pthread rwlock t *l ); • zruˇs´ız´amek int pthread rwlock rdlock(pthread rwlock t *l ); int pthread rwlock tryrdlock(pthread rwlock t *rwlock ); • zamkne z´amekpro ˇcten´ı(v´ıcevl´aken m˚uˇzedrˇzetz´amekpro ˇcten´ı),pokud m´anˇekdoz´amekpro z´apis,usp´ıvolaj´ıc´ıvl´akno (rdlock()) resp. vr´at´ıchybu (tryrdlock()).

• nen´ısouˇc´ast´ıPOSIXov´ych vl´aken z POSIX.1c, ale POSIX.1j rozˇs´ıˇren´ı,naz- van´e“advanced realtime extensions”. • najednou m˚uˇzem´ıtz´amekbud’ nˇekolik vl´aken zamˇcenopro ˇcten´ınebo ma- xim´alnˇejedno vl´akno zamˇcenopro z´apis(a nikdo pro ˇcten´ı). • read-write z´amkyjsou semanticky podobn´ezamyk´an´ısoubor˚upomoc´ıfunkce fcntl. • Je bˇeˇzn´e,ˇze implementace preferuje vl´akna,kter´achtˇej´ızapisovat pˇredvl´akny, kter´achtˇej´ıˇc´ıst. Napˇr.pokud je z´amekvlastnˇen´yzapisovatelem a nˇejak´e dalˇs´ıvl´akno zavol´a pthread rwlock rdlock a existuje aspoˇnjedno vl´akno ˇcekaj´ıc´ıv pthread rwlock wrlock, d´aˇcten´aˇrpˇrednostzapisovateli.

• Existuje maxim´aln´ı poˇcetzamˇcen´ı pro ˇcten´ı dan´yimplementac´ı (velikost´ı typu reprezentuj´ıc´ıhopoˇcetzamˇcen´ı),po dosaˇzen´ımaxima vrac´ı pthread rwlock rdlock hodnotu EAGAIN.

233 Read-write z´amky(2)

int pthread rwlock wrlock(pthread rwlock t *rwlock ); • zamkne z´amekpro z´apis;pokud m´anˇekdoz´amekpro ˇcten´ı nebo z´apis,ˇcek´a.

int pthread rwlock trywrlock(pthread rwlock t *rwlock ); • jako pthread rwlock wrlock(), ale kdyˇznem˚uˇzezamknout, vr´at´ıchybu.

int pthread rwlock unlock(pthread rwlock t *rwlock ); • odemkne z´amek

• zvl´aˇstnost: pokud vl´aknoˇcekaj´ıc´ı na z´amekdostane sign´al,po n´avratuz handleru se vˇzdypokraˇcujev ˇcek´an´ı,tj. nenastane chyba EINTR. Takto se chovaj´ıi mutexy a podm´ınkov´epromˇenn´e.

234 Atomick´earitmetick´eoperace

• pro architektury, kde operace sˇc´ıt´an´ınen´ıatomick´a • v´yraznˇerychlejˇs´ıneˇzjin´emechanismy pro z´ısk´an´ıexkluzivn´ıho pˇr´ıstupud´ıkypouˇzit´ıinstrukc´ına dan´eplatformˇezajiˇst’uj´ıc´ıch atomicitu. • nˇekter´esyst´emy dod´avaj´ıfunkce pro atomick´eoperace, (napˇr. atomic add(3c) v Solarisu), obecnˇeje lepˇs´ıpouˇz´ıtpodporu v C11 standardu pˇres stdatomic.h. • sada vol´an´ıpro r˚uzn´etypy a operace, napˇr.sˇc´ıt´an´ı: #include

atomic_int acnt; atomic_fetch_add(&acnt, 1);

• Pˇr´ıklad race/atomic-add.c demonstruje probl´emse soubˇehempˇrisˇc´ıt´an´ı a jeho moˇzn´aˇreˇsen´ı.Program spust´ıdvˇevl´akna,kaˇzd´evl´aknopracuje se stejnou glob´aln´ı promˇennou x, do kter´ev cyklu postupnˇepˇriˇcteˇc´ısla od jedn´edo velikosti parametru arg, kter´yprogram dostane na pˇr´ıkazov´eˇr´adce. Vl´aknabˇeˇz´ıparalelnˇe, kaˇzd´ez nich prov´ad´ıtoto:

for (i = 1; i < arg; ++i) x = x + i;

Pot´ese sˇc´ıt´an´ıpro kontrolu provede v hlavn´ımvl´aknu, a dvojn´asobek (mˇeli jsme dva thready) se porovn´as hodnotou glob´aln´ıpromˇenn´e x. Pokud nejsou v´ysledkystejn´e,doˇslok soubˇehu (pˇreteˇcen´ıpromˇenn´em˚uˇzemev t´etosituaci zcela ignorovat). V´ysledkya ˇcasybˇehu se markantnˇeliˇs´ı pro situace, kdy program pouˇzil obyˇcejn´esˇc´ıt´an´ı,funkci pro atomickou aritmetiku a zamyk´an´ıpomoc´ımu- tex˚u.Je vidˇetnˇekolikan´asobn´yrozd´ılv dobˇebˇehu mezi pouˇzit´ımfunkce pro atomickou aritmetiku a mutex˚u,zejm´enana procesorech hardwarovou pod- porou paralelismu. • Podobnˇeexistuj´ıdalˇs´ıatomick´erutiny pro odeˇc´ıt´an´ı,bitov´eoperace AND a OR, pro pˇriˇrazen´ıhodnoty atd.

235 Bari´era • bari´era(barrier) je zp˚usob,jak udrˇzetˇcleny skupiny pohromadˇe • vˇsechna vl´akna ˇcekaj´ına bari´eˇre,dokud ji nedos´ahneposledn´ı vl´akno;pak mohou pokraˇcovat • typick´epouˇzit´ıje paraleln´ızpracov´an´ıdat int pthread barrier init(pthread barrier t *barrier, attr, unsigned count ); • inicializuje bari´erupro count vstup˚udo n´ı int pthread barrier wait(pthread barrier t *barrier ); • zablokuje se dokud nen´ızavol´ana count-kr´at int pthread barrier destroy(pthread barrier t *barrier ); • zruˇs´ıbari´eru

• API pro bari´eryje definovan´eod SUSv3, pod´ıvejte se napˇr´ıkladna pthread - barrier init, je moˇzn´eje ale jednoduˇsevytvoˇritpomoc´ımutex˚ua podm´ın- kov´ych promˇenn´ych. • Pozor na to, ˇzebari´eryjsou nepovinnou ˇc´ast´ıPOSIXu (patˇr´ıdo Advanced realtime threads) a tedy i syst´emcertifikovan´yna SUS je nemus´ıimplemen- tovat, coˇzje pˇr´ıpadMac OS X (10.10). • bari´erum˚uˇzetevyuˇz´ıtnapˇr.v situaci, kdy mezi jednotliv´ymif´azemizpra- cov´an´ıje potˇrebaprov´estjistou inicializaci, vl´aknapˇredn´ıtedy na sebe vˇzdy mus´ıpoˇckat, protoˇzeinicializace dalˇs´ıf´azem˚uˇze zaˇc´ıtaˇztehdy, kdy skonˇc´ı f´azepˇredchoz´ı.Pˇr´ıklad pthreads/pthread-barrier.c ukazuje pouˇzit´ıba- ri´erypro nˇekolik f´az´ızpracov´an´ıdat.

• podm´ınka pro bari´eruje napˇr´ıkladhodnota ˇc´ıtaˇcerovnaj´ıc´ıse nule. Kaˇzd´e vl´akno,kter´edos´ahnebari´ery, sn´ıˇz´ıˇc´ıtaˇc,kter´yje na zaˇc´atku inicializov´an na poˇcet vl´aken. Pokud vl´aknopo dekrementov´an´ı ˇc´ıtaˇce zjist´ı, ˇze jeˇstˇe nen´ıroven nule, usp´ıse na podm´ınkov´epromˇenn´e.Pokud dan´evl´aknoje t´ımvl´aknem,kter´esn´ıˇz´ıˇc´ıtaˇcna nulu, m´ıstozavol´an´ı pthread cond wait poˇsle broadcast, kter´yn´aslednˇe probud´ı vˇsechna vl´aknasp´ıc´ı na bari´eˇre (pthread cond signal zde nestaˇc´ı,chcete probudit vˇsechna vl´akna,ne jen jedno!). Pˇredspuˇstˇen´ımdalˇs´ıf´azezpracov´an´ıse ˇc´ıtaˇcreinicializuje na p˚uvodn´ı hodnotu. I zde je nutn´eˇreˇsitr˚uzn´eprobl´emy, napˇr´ıkladnen´ımoˇzn´ejen tak reinicializovat ˇc´ıtaˇcpot´e,co bari´erydos´ahneposledn´ıvl´akno,protoˇzejak jiˇz v´ıme,vl´aknapo probuzen´ız pthread cond wait mus´ıvˇzdyotestovat, zda ˇc´ıtaˇcje opravdu nulov´ya pokud nen´ı,opˇetse usp´ı.Takˇzeby se v´ammohlo

236 st´at,ˇzeby se probudila jen nˇekter´avl´akna,nebo taky ˇz´adn´a.Je nutn´ezre- setovat ˇc´ıtaˇcaˇzpo probuzen´ıposledn´ıhovl´akna.Jak byste to ˇreˇsili?

Semafory

• semafory poch´az´ız POSIX-1003.1b (real-time extensions)

• jm´enafunkc´ınezaˇc´ınaj´ı pthread , ale sem (sem init, sem post, sem wait,...) • je moˇzn´eje pouˇz´ıts vl´akny

• funkce pro semafory se drˇz´ıklasick´eUNIXov´es´emantiky – pˇrichybˇevracej´ı -1 a nastav´ı errno

237 Typick´epouˇzit´ıvl´aken

• pipeline – kaˇzd´ez vl´aken prov´ad´ısvoji operaci nad daty, kter´ase postupnˇepˇred´avaj´ımezi vl´akny – kaˇzd´evl´aknotypicky prov´ad´ıjinou operaci ... zpracov´an´ıobr´azku,kde kaˇzd´evl´aknoprovede jin´yfiltr • work crew – vl´aknaprov´adˇej´ıstejnou operaci, ale nad jin´ymidaty ... zpracov´an´ıobr´azkudekompozic´ı– kaˇzd´evl´aknozpracov´av´a jinou ˇc´astobr´azku,v´ysledkem je spojen´ızpracovan´ych dat ze vˇsech vl´aken; zde se hod´ıˇreˇsen´ıs bari´erou • client – server

• dan´erozdˇelen´ıje jen orientaˇcn´ı,pouˇzit´ıvl´aken je samozˇrejmˇeneomezen´e, toto jsou asi ty tˇrinejˇcastˇejˇs´ıpouˇzit´ı • V pˇr´ıpadˇemodelu klient – server zpracov´av´akaˇzd´evl´aknojeden poˇzadavek od jednoho klienta.

238 Thread-safe versus reentrantn´ı

• thead-safe znamen´a,ˇzek´odm˚uˇzeb´ytvol´anz v´ıcevl´aken najednou bez destruktivn´ıch n´asledk˚u – do funkce, kter´anebyla navrˇzenajako thread-safe, je moˇzn´e pˇridatjeden z´amek– na zaˇc´atkufunkce se zamkne, na konci odemkne – tento zp˚usobale samozˇrejmˇenen´ıpˇr´ıliˇsefektivn´ı • slovem reentrantn´ı se typicky mysl´ı,ˇzedan´afunkce byla navrˇzenas pˇrihl´ednut´ımna existenci vl´aken – . . . tedy ˇzefunkce pracuje efektivnˇei ve v´ıcevl´aknov´em prostˇred´ı – takov´afunkce by se mˇelavyvarovat pouˇzit´ıstatick´ych dat a pokud moˇznoi prostˇredk˚upro synchronizaci vl´aken, protoˇze bˇehaplikace zpomaluj´ı

• z v´yˇse uveden´ehovypl´yv´a,ˇzethread-safe je slabˇs´ıvlastnost neˇzreentrantn´ı. Napsat thread-safe funkci lze s pouˇzit´ımsynchronizaˇcn´ıch primitiv; pˇreps´an´ı existuj´ıc´ıfunkci tak, aby byla reentrantn´ıvyˇzadujemnohem v´ıceinvence. • reentrantn´ıfunkce jsou tak´ejedin´efunkce bezpeˇcnˇepouˇziteln´ev signal han- dlerech.

• v dneˇsn´ıdobˇethread-safe vˇetˇsinouznamen´areentrantn´ı,tj. funkce jsou pˇre- ps´any tak, aby pracovaly efektivnˇei s vl´akny, je ale dobr´evˇedˇet,ˇzenˇekdyto m˚uˇzevyjadˇrovat rozd´ıl. • o zamyk´an´ıknihoven viz tak´estrana 228.

• existuje mnoˇzstv´ıfunkc´ı,kter´emohou b´ytthread-safe, ale nikoliv reentrant, napˇr. gethostbyname. Bˇeˇznˇetato funkce pouˇz´ıv´astatickou promˇennou, kter´a se znovu pouˇzijepˇrikaˇzd´emvol´an´ı,takˇzeje pro pouˇzit´ıv multithreadov´em prostˇred´ı nevhodn´e- nen´ı thread-safe. Nicm´enˇe,na FreeBSD 6.0 je tato funkce implementovan´atak, ˇzepouˇz´ıv´aimplicitnˇethread-local storage pro uloˇzen´ı v´ystupn´ıch dat a t´ım p´ademje thread safe. To ji jeˇstˇeale neˇcin´ı ´uplnˇebezpeˇcnouk pouˇzit´ı(nemluvˇeo tom, ˇzeprogram , kter´yse spol´eh´ana takov´echov´an´ınen´ıportabiln´ı),viz pˇr´ıklad reentrant/gethostbyname.c . O nˇecolepˇs´ıje pouˇz´ıtreentrantn´ıverzi t´etofunkce gethostbyname r (po- kud je na dan´emsyst´emu k dispozici), u kter´elze specifikovat adresu, kam m´aukl´adatsv˚ujv´ystup,ˇc´ımˇzse st´av´areentrantn´ı.Daleko nejlepˇs´ıˇreˇsen´ıje pouˇz´ıtstandardn´ıfunkci getaddrinfo (viz strana 200), kter´aje sama o sobˇe reentrantn´ı.

239 • pˇr´ıklad: reentrant/inet ntoa.c - tady je vidˇet,ˇzeani takto napsan´a funkce v´amnepom˚uˇzepokud je volan´advakr´atv r´amcijednoho vol´an´ı printf. Pokaˇzd´evrac´ıpointer se stejnou adresou (v jednom threadu), kterou si printf pouze poznamen´aa pˇrifin´aln´ımtisku tedy vyp´ıˇse reprezentaci posledn´ıad- resy, se kterou byla inet ntoa vol´ana.Na Solarisu je to vidˇetpomoc´ı:

truss -t\!all -u libnsl::inet_ntoa ./a.out

• Na Solarisu obsahuj´ımanu´alov´estr´ankyknihovn´ıch funkc´ıpoloˇzku MT-level v sekci ATTRIBUTES, kter´aud´av´azda je moˇzn´efunkci pouˇz´ıtv multithrea- dov´emprostˇred´ıa pˇr´ıpadnˇes jak´ymiomezen´ımi.Tyto ´urovnˇejsou pops´any v manu´alov´estr´anceattributes(5).

Nepˇrenositeln´avol´an´ı

• nepˇrenositeln´avol´an´ıkonˇc´ıˇretˇezcem np (non-portable) a jednotliv´esyst´emy si takto definuj´ıvlastn´ıvol´an´ı • FreeBSD – pthread set name np(pthread t tid, const char *name) → umoˇzˇnujepojmenovat vl´akno • Solaris – pthread cond reltimedwait np(...) → jako timedwait, ale ˇcasov´ytimeout je relativn´ı • OpenBSD – int pthread main np(void) → umoˇzˇnujezjistit, zda volaj´ıc´ıvl´aknoje hlavn´ı(= main())

• Tyto informace jsou pro zaj´ımavost, abyste vˇedˇeli,ˇzese s podobn´ymivˇecmi m˚uˇzetesetkat. Nepˇrenositeln´avol´an´ı by se mˇelapouˇz´ıvat sp´ıˇsepro lad´ıc´ı ´uˇcely. Nikdy nev´ıte,kdo bude potˇrebovat v´aˇsk´odspustit na jin´emsyst´emu, coˇzse stane typicky a neˇcekanˇepo t´e,co zrovna opust´ıtevaˇsi spoleˇcnosta nem´atejiˇzˇcasto opravit. • Zjistit, jak´anepˇrenositeln´avol´an´ıv´aˇssyst´emposkytuje je jednoduch´e,tˇreba pomoc´ı apropos np, nebo o nˇecohrubˇeji(aplikujte na sv˚ujsyst´empodle lokace manu´alov´ych str´anek):

$ cd /usr/share/man $ find . -name ’*_np\.*’ ./man3c/mq_reltimedreceive_np.3c

240 ./man3c/mq_reltimedsend_np.3c ./man3c/posix_spawnattr_getsigignore_np.3c ./man3c/posix_spawnattr_setsigignore_np.3c ./man3c/pthread_cond_reltimedwait_np.3c ./man3c/pthread_key_create_once_np.3c ./man3c/pthread_mutex_reltimedlock_np.3c ./man3c/pthread_rwlock_reltimedrdlock_np.3c ./man3c/pthread_rwlock_reltimedwrlock_np.3c ./man3c/sem_reltimedwait_np.3c

241 ChangeLog

2017-10-24 We started translating this text to English. First, we will translate slides, and we will go through all the notes after that. It will take some time to finish it all. Some of the file API slides were translated in this revision. 2017-10-02 SUSv4 2017-07-23 pouze zmˇeny v sazbˇe. 2017-01-01 oprava textu o tom, ˇzeje moˇzn´esignalizovat podm´ınkovou promˇennoumimo kritickou sekci, p211. P˚uvodn´ıtext chybnˇevysvˇetloval, ˇzetakov´yk´odnen´ıspr´avnˇenaps´an. 2016-12-12 pozn´amka o C11 a stdatomic.h 2016-11-28 pˇrid´anpˇr´ıklad tcp/linger.c

2016-11-07 pˇrid´anpˇr´ıklad signals/check-existence.c 2016-02-25 pozn´amka k pouˇzit´ı O EXCL bez O CREAT, p93 2016-01-13 pozn´amkyk implementac´ırwlock z´amk˚u,p233 2015-12-15 pˇrid´anpˇr´ıklad signals/event-loop.c 2015-12-12 serie mal´ych oprav 2015-10-22 pˇrid´anpˇr´ıklad main/putenv.c 2014-12-17 pozn´amkyk rekurzivn´ımmutex˚um,p226 2014-12-16 pˇrid´anpˇr´ıkladna velikost stacku u pthread˚u pthreads/pthread-stack-overflow.c , p215 2014-12-16 ´uprava k´oduTCP klienta a rozˇs´ıˇreny pozn´amky o hyb´ach pro TCP server a klient, p201, p202 2014-12-15 zobecnˇenslajd na stranˇe 235 o atomick´ych aritmetick´ych operac´ıch, pˇr´ıklad race/atomic-add.c pˇreps´anaby fungoval jak na Solarisu, tak OS X. 2014-12-15 pozn´amka k IPv4-mapped IPv6 adres´ach u pˇr´ıkladuTCP serveru, p201. 2014-12-15 vyjmut slajd o legacy/obsolete funkc´ıch gethostbyname a gethostbyaddr. 2014-12-12 r˚uzn´epozn´amkyk socket API 2014-02-13 pˇrid´anpˇr´ıklad pthreads/pthread-barrier.c a vysvˇetlen´ıAPI k POSIX bari´er´am,p236.

2013-11-28 pˇrid´anpˇr´ıklad file-locking/lockf.c a pozn´amkyk mandatory lockingu, p168.

2013-11-18 v´ıcepozn´amekk OS X, pˇr´ıklad session/getppid.c

2013-11-12 v´ıcek mmap(), pˇr´ıklad mmap/aligned.c 2013-11-11 podrobnˇejˇs´ıvysvˇetlen´ık priorit´amproces˚u 2013-10-21 pozn´amka k rekurzivn´ımu maz´an´ıadres´aˇreu knihovn´ıhovol´an´ı rmdir 2013-05-31 pˇrid´anpˇr´ıklad inetd/accept-rw.c a v´ıceinformac´ık inetd, p208.

2013-01-01 v´ıcedetail˚uk fungov´an´ık pthread atfork, pthreads/atfork.c , p223. 2012-12-18 pozn´amka k vytv´aˇren´ıthread˚uv cyklu, p215 2012-12-05 pˇrid´anpˇr´ıklad resolving/getbyname.c , p199 a koment´aˇrk funkc´ımprohled´avaj´ıc´ımda- tab´azesluˇzeba protokol˚u 2012-11-28 pˇrid´anpˇr´ıklad race/fcntl-fixed-race.c , p169

2012-11-21 pˇrid´anpˇr´ıklad signals/sigqueue.c

2012-11-14 pˇrid´anpˇr´ıklad mmap/lseek.c k mmap 2012-01-30 priklady jsou nyni odkazy na web 2012-01-22 pˇrid´any pozn´amkyk tread-safe/reentrant funkc´ıma odkazy na pˇr´ıklady reentrant/gethostbyname.c , reentrant/inet ntoa.c , p239.

242 2012-01-16 slajd o bari´eˇrea semaforech rozdˇelenna dva, p236 2012-01-16 pˇrid´anatabulka shrnuj´ıc´ıchov´an´ıjednotliv´ych typ˚umutex˚u,p227. 2012-01-13 pozn´amka o zp˚usobuimplementace POSIX threads a knihovn´ach, kter´etoto API nab´ızej´ı, p213 2012-01-13 pozn´amka o d˚uleˇzitostifunkce scheduleru pˇri implementaci synchronizaˇcn´ıch primitiv 2012-01-11 pˇrid´anodkaz na pˇr´ıklad pthreads/set-detachstate.c 2012-01-11 rozveden popis pouˇzit´ıfunkce pthread atfork, p223. 2012-01-10 pˇreformulov´ankoment´aˇrk slajdu s pˇr´ıkladempro atomic add, p235. 2012-01-10 pˇr´ıkladna neblokuj´ıc´ı connect pˇresunut za vol´an´ı getsockopt a select. 2012-01-05 pˇreps´any slajdy s pˇr´ıkladypro TCP klient a server tak aby nebyly specifick´epro ˇz´adnou address family 2012-01-04 pˇrid´anpˇr´ıklad resolving/getnameinfo.c , doplnˇeny slajdy pro funkce getnameinfo a getaddrinfo na str´ank´ach 201a 200. 2012-01-03 pˇr´ıkladypro vyˇsˇs´ıgranularitu sleep byly pˇresunuty do samostatn´ehoadres´aˇre resolving 2011-12-22 upˇresnˇen´ık wildcard soket adres´amu vol´an´ı bind 2011-12-21 pˇrid´anpˇr´ıklad tcp/reuseaddr.c pro demonstraci parametru SO REUSEADDR vol´an´ı setsockopt 2011-11-24 nov´yslajd o setpgid a setsid 2011-11-23 pozn´amkyk form´atuspustiteln´ych soubor˚u a.out 2011-11-09 pozn´amkyk pˇresmˇerov´an´ıa tabulce deskriptor˚u 2011-11-07 Pˇrid´any PDF bookmarks druh´ehoˇr´aduk definic´ımfunkc´ıa d˚uleˇzit´ymslajd˚um. 2011-11-07 Ot´azka k fstat 2011-11-02 Doplnˇeny informace o /etc/passwd a /etc/shadow. Pˇrid´anslajd p 68 s funkcemi pro z´ısk´av´an´ı´udaj˚uo uˇzivatel´ıch/skupin´ach (getpwent apod.) 2011-10-26 Zm´ınˇen chroot, kosmetick´eopravy v sekci o API pro soubory. 2011-10-19 Pˇrid´anpˇr´ıklad exit/exit.c a informace o promˇenn´eprostˇred´ı LD LIBRARY PATH. 2011-10-18 Aktualizace informac´ıo souˇcasn´ych unixov´ych syst´emech, pˇrid´anop´ar detail˚uk historii. 2011-10-17 Upravy´ stylu (linky, pˇr´ıklady, PDF bookmarks). 2011-01-08 Nov´ypˇr´ıklad mutexes/not-my-lock.c , p227. 2010-10-23 Pozn´amka o funkci znaku ‘-’ ve jm´enˇeshellu v argv[0], p48. 2010-10-21 Nov´epˇr´ıklady read/lseek.c , p100, read/big-file.c , p100, read/redirect.c , p103, stat/filetype.c a stat/stat.c , p106.

2010-10-20 Nov´ypˇr´ıklad read/cat.c , p96.

2010-10-15 Nov´ypˇr´ıklad err/err.c , p63. 2010-03-07 Upˇresnˇen´ıinformac´ıohlednˇezachyt´av´an´ısynchronn´ıch sign´al˚u,p150ap224, a nov´ypˇr´ıklad signals/catch-SIGSEGV.c . 2010-03-06 Pˇrid´any informace o sigwait vol´an´ıvzhledem k synchronn´ımsign´al˚um,p224. Nov´ypˇr´ıklad pthreads/sigwait-with-sync-signals.c . 2010-02-28 Drobn´e´upravy. 2010-01-11 V´ıceo errno pˇripouˇzit´ıs vl´akny, p214. 2009-12-13 Nov´epˇr´ıklady select/busy-waiting.c , p204, select/write-select.c , p206a tcp/addresses.c , p192. 2009-12-06 Nov´ypˇr´ıklad signal/signal-vs-sigaction.c , p155, zm´ınˇenomakro SOMAXCONN. 2009-10-11 Nov´epˇr´ıkladyodkazovan´ez ˇc´astipro prvn´ıpˇredn´aˇsku. 2009-10-06 Drobn´efixy, pˇrid´an´ıVl´adiKotala jako vyuˇcuj´ıc´ıhotohoto pˇredmˇetupro letoˇsn´ırok. 2009-02-13 Zm´ınˇenovol´an´ı remove(3), p114. 2009-02-06 Nov´ypˇr´ıklad tcp/non-blocking-connect.c , p205.

243 2009-01-14 Nov´epˇr´ıklady z adres´aˇre main, p49, lib-abi/abi-main.c , p38, exec/exec-date.c , p132, getaddrinfo/gethostbyname.c , getopt/getopts.sh a getopt/getopt.c , p54.

2009-01-13 Nov´eslajdy getaddrinfo, p200, getnameinfo, p201, nov´epˇr´ıklady cond-variables/queue-simulation.c , p232, getaddrinfo/getaddrinfo.c , p200. 2009-01-10 Nov´yslajd, kter´yuv´ad´ıcelou sekci o vl´aknech, p213, a obsahuje nˇekter´eobecn´einformace, kter´eby jinak nebyly zd˚uraznˇeny. Nov´epˇr´ıklady mutexes/race.c a mutexes/race-fixed.c , p228. 2009-01-06 Pˇrid´anazm´ınka o privilege separation, p211, pˇrid´any pˇr´ıklady pthreads/setjmp.c , p212, pthreads/wrong-use-of-arg.c a pthreads/correct-use-of-arg.c , p215, pthreads/int-as-arg.c , p215, pthreads/pthread-join.c a pthread-detach-join.c , p218, pthreads/pthread-cancel.c , p219, pthreads/fork.c , pthreads/fork-not-in-main.c , a pthreads/forkall.c , p223, a pthreads/sigwait.c , p224.

2008-12-16 Nov´eslajdy o adresn´ıch struktur´ach pro s´ıt’ovou komunikaci, p188, a o pˇrevodech adres z bin´arn´ıreprezentace na ˇretˇezcea naopak, p191. Pˇrid´any pˇr´ıkladyna TCP, tcp/up-to-listen-only.c , p190, tcp/tcp-sink-server.c , p191, tcp/connect.c , p192, a UDP, udp/udpclient.c , p194, udp/udp-server.c , p194. Pˇr´ıkladpro pr´acis v´ıcedeskriptory, select/select.c , p205, a alternativn´ıpouˇzit´ıvol´an´ı poll v select/poll-sleep.c , p207.

2008-12-09 Pˇr´ıklady file-locking/lock-unlock.c , p167, file-locking/fcntl-locking.c , p169, semaphores/sem-fixed-race.c , p177.

2008-12-01 Pˇr´ıklad dyn-lib/rtld next.c , p145

2008-11-30 Pˇr´ıklady signals/killme.c , p148, signals/catch-SIGKILL.c , p??, signals/ctrl-z.c , p152, signals/sa sigaction.c , p155, race/race.c , p161. 2008-11-28 Pozn´amka k return (-1), p49. Doplnˇen´ıpozn´amekk dynamick´emu linkov´an´ı.Nov´epˇr´ıkla- dy: dyn-lib/ld-lazy.c a dyn-lib/dlopen.c , p144, signals/alarm.c , p156, signals/sigwait.c , p159. 2008-11-22 d type, nepˇrenositeln´apoloˇzka struktury dirent, p113. Nov´yslajd s uk´azkou konkr´etn´ıho adresov´ehoprostoru procesu, p118, a k tomu pˇr´ıklad pmap/proc-addr-space.c .

2008-11-19 Nov´ypˇr´ıklad wait/wait.c , p135, a doplnˇen´ıpozn´amekke stejn´emu slajdu. Nov´epˇr´ıklady fork/fork.c a fork/vfork.c , p130. 2008-11-11 Zaˇcaljsem postupnˇepˇrid´avat odkazy na pˇr´ıkladyk jednotliv´ymslajd˚um.Pokud je tedy v pozn´amk´ach uvedeno ,,pˇr´ıklad: readdir/readdir.c ”, znamen´ato, ˇzepˇr´ıkladnajdete zde: http://mff.devnull.cz/pvu/src/readdir/readdir.c 2008-11-06 Pˇrid´any r˚uzn´epozn´amkyk API pro pr´acise soubory. Nov´yslajd pˇredstavuj´ıc´ı funkce err(3), p63. 2008-10-21 Pˇrid´anpˇr´ıkladbin´arn´ınekompatibility OpenSSL knihoven r˚uzn´ych verz´ıv dneˇsn´ıch sys- t´emech, p39. 2008-10-04 Pˇrid´any r˚uzn´epozn´amkya doplnˇen´ıpˇrikontrole pˇredprvn´ıpˇredn´aˇskou nov´ehosemestru, napˇr´ıklad uk´azka na nespr´avn´epouˇzit´ı execl vol´an´ı, p132, nebo upozornˇen´ı na to, ˇze jak´ekoli ˇreˇsen´ıpro synchronizaci pomoc´ıaktivn´ıho ˇcek´an´ınen´ıpˇrizkouˇsceakceptov´ano, p167, 204. 2008-09-05 Zm´ınˇenavol´an´ı setjmp a longjmp, p212 2008-03-30 Pˇrid´any informace k m´od˚um RTLD LAZY a RTLD NOW pro vol´an´ı dlopen, p144. 2008-03-23 Pˇrid´anapozn´amka k maz´an´ısoubor˚ua sticky bitu, p69, v´ıceinformac´ık SIGKILL, p151, k async-signal-safe funkc´ım,p154, k aktivn´ımu ˇcek´an´ıpˇrisynchronizaci, p165, pˇr´ıkladna deadlock, p170. 2008-03-01 Drobn´adoplnˇen´ık sign´al˚um.Pˇrid´anapozn´amka o funkc´ıch sigwaitinfo(3) a sigtimed- wait(3), p159.

244 2008-02-29 Pˇrid´ansamostatn´yslajd o POSIXu, p15. 2008-02-17 Mnoho oprav r˚uzn´ych chyb a jin´ych nepˇresnost´ı. Pˇrid´anainformace o POSIX.4, p155. DˇekujuMartinovi Horˇciˇckovi (martin at horcicka dot eu) za feedback. 2008-01-25 Mal´eopravy v sazbˇetextu, pˇrid´an´ı kˇr´ıˇzov´ych odkaz˚u,drobn´adoplnˇen´ı pozn´amekna r˚uzn´ych m´ıstech apod. 2007-12-29 Doplnˇen´ıdefinice kritick´esekce (p163), pˇrid´an´uvodn´ıslajd k synchronizaci vl´aken (p225), doplnˇeny informace o r˚uzn´ych typech mutex˚u(p226), doplnˇeny pozn´amkyk podm´ınkov´ym promˇenn´ym. 2007-12-12 Pˇrid´anomnoho nov´ych pozn´amekke slajd˚umo s´ıt’ov´ekomunikaci. 2007-12-09 Pˇrid´anslajd pro atomic add(3c) v sekci synchronizace vl´aken, p235. 2007-11-21 R˚uzn´adoplnˇen´ık sign´al˚umna slajdech i v pozn´amk´ach. 2007-11-18 Opraveny dalˇs´ı v´yskyty znaku ‘0’ m´ıstoˇretˇezce‘len’, tentokr´at na slajdech k mmap(2) vol´an´ı. 2007-11-07 Pˇrid´ankonkr´etn´ıpˇr´ıkladk pozn´amk´amo soft updates. 2007-10-23 Nov´yslajd ,,API vers ABI”, p37, a doplnˇen´ıpozn´amekk z´apisudo pojmenovan´eroury, p98. 2007-10-15 Doplnˇeny pozn´amky ke slajd˚umo promˇenn´ych prostˇred´ıa ˇcten´ı/z´apisuz/do roury, kde byly i faktick´echyby. 2007-10-07 C´asteˇcnˇepˇreps´anyˇ pozn´amkyke slajd˚umo historii unixu, standardech a souˇcasn´ych sys- t´emech; doplnˇeny pozn´amkyk dynamick´emu linkeru, debugger˚uma C. 2007-09-16 Vyˇrazenakapitola o administraci, bude nahrazeno nˇeˇc´ımjin´ym,pravdˇepodobnˇeaplikac´ı autoconf. 2007-09-16 Opravy pˇreklep˚u,gramatick´ych chyb a pod. D´ıkyHonzovi Friedlovi (frido at devnull dot cz) 2007-07-18 Do tˇechto materi´al˚ubyl pˇrid´anChangeLog pro snadnˇejˇs´ısledov´an´ızmˇen.Generov´an´ıto- hoto textu bylo z´aroveˇnpˇresunuto z FreeBSD na Solaris a v souvislosti s t´ımjsem pˇreˇsel z CsLaTeX na Babel. M˚uˇze to ovlivnit nˇekter´efonty a t´ımi sazbu textu.

245 The End.

246