-------------------+ Risunok 7.23. Algoritm vydeleniya oblastej komand fajl, svyazannyj s oblast'yu. Esli by znachenie schetchika ssylok stalo ravnym 0, 210 yadro moglo by peredat' kopiyu indeksa v pamyati drugomu fajlu, tem samym delaya somnitel'nym znachenie ukazatelya na indeks v zapisi tablicy oblastej: esli by pol'zovatelyu prishlos' ispolnit' novyj fajl, ispol'zuya funkciyu exec, yadro po oshibke svyazalo by ego s oblast'yu komand starogo fajla. |ta problema ustranya- etsya blagodarya tomu, chto yadro pri vypolnenii algoritma allocreg uvelichivaet znachenie schetchika ssylok na indeks, preduprezhdaya tem samym perenaznachenie indeksa v pamyati drugomu fajlu. Kogda process vo vremya vypolneniya funkcij exit ili exec otsoedinyaet oblast' komand, yadro umen'shaet znachenie schetchika ssylok na indeks (po algoritmu freereg), esli tol'ko svyaz' indeksa s ob- last'yu ne pomechena kak "neot®emlemaya". Tablica indeksov Tablica oblastej +----------------+ chto moglo by proi- +----------------+ | - | zojti, esli by schet- | - | | - | chik ssylok na indeks | - | | - | fajla /bin/date byl | - | | - | raven 0 +----------------+ | - | | oblast' komand | | - | -- - - - - -|- dlya fajla | | - | | | /bin/who | +----------------+ - +----------------+ | kopiya indeksa -|- - - - - -+ | - | | fajla /bin/date| | - | | v pamyati <+-----------+ | - | +----------------+ | +----------------+ | - | | | oblast' komand | | - | +-----------+- dlya fajla | | - | ukazatel' na| /bin/date | | - | kopiyu indek-+----------------+ | - | sa v pamyati | - | | - | | - | +----------------+ +----------------+ Risunok 7.24. Vzaimosvyaz' mezhdu tablicej indeksov i tablicej oblastej v sluchae sovmestnogo ispol'zovaniya processami odnoj oblasti komand Rassmotrim v kachestve primera situaciyu, privedennuyu na Risunke 7.21, gde pokazana vzaimosvyaz' mezhdu strukturami dannyh v processe vypolneniya funkcii exec po otnosheniyu k fajlu "/bin/date" pri uslovii raspolozheniya komand i dan- nyh fajla v raznyh oblastyah. Kogda process ispolnyaet fajl "/bin/date" pervyj raz, yadro naznachaet dlya komand fajla tochku vhoda v tablice oblastej (Risunok 7.24) i po zavershenii vypolneniya funkcii exec ostavlyaet schetchik ssylok na indeks ravnym 1. Kogda fajl "/bin/date" zavershaetsya, yadro zapuskaet algorit- my detachreg i freereg, sbrasyvaya znachenie schetchika ssylok v 0. Odnako, esli yadro v pervom sluchae ne uvelichilo znachenie schetchika, ono po zavershenii funk- cii exec ostanetsya ravnym 0 i indeks na vsem protyazhenii vypolneniya processa budet nahodit'sya v spiske svobodnyh indeksov. Predpolozhim, chto v eto vremya svobodnyj indeks ponadobilsya processu, zapustivshemu s pomoshch'yu funkcii exec fajl "/bin/who", togda yadro mozhet vydelit' etomu processu indeks, ranee pri- nadlezhavshij fajlu "/ bin/date". Prosmatrivaya tablicu oblastej v poiskah in- deksa fajla "/bin/who", yadro vmesto nego vybralo by indeks fajla "/bin/date". Schitaya, chto oblast' soderzhit komandy fajla "/bin/who", yadro is- polnilo by sovsem ne tu programmu. Poetomu znachenie schetchika ssylok na in- deks aktivnogo fajla, svyazannogo s razdelyaemoj oblast'yu komand, dolzhno byt' ne men'she edinicy, chtoby yadro ne moglo perenaznachit' indeks drugomu fajlu. Vozmozhnost' sovmestnogo ispol'zovaniya razlichnymi processami odnih i teh zhe oblastej komand pozvolyaet ekonomit' vremya, zatrachivaemoe na zapusk prog- rammy s pomoshch'yu funkcii exec. Administratory sistemy mogut s pomoshch'yu sistem- 211 noj funkcii (i komandy) chmod ustanavlivat' dlya chasto ispolnyaemyh fajlov re- zhim "sticky-bit", sushchnost' kotorogo zaklyuchaetsya v sleduyushchem. Kogda process ispolnyaet fajl, dlya kotorogo ustanovlen rezhim "sticky-bit", yadro ne osvobozh- daet oblast' pamyati, otvedennuyu pod komandy fajla, otsoedinyaya oblast' ot processa vo vremya vypolneniya funkcij exit ili exec, dazhe esli znachenie schet- chika ssylok na indeks stanovitsya ravnym 0. YAdro ostavlyaet oblast' komand v pervonachal'nom vide, pri etom znachenie schetchika ssylok na indeks ravno 1, pust' dazhe oblast' ne podklyuchena bol'she ni k odnomu iz processov. Esli zhe fajl budet eshche raz zapushchen na vypolnenie (uzhe drugim processom), yadro v tab- lice oblastej obnaruzhit zapis', sootvetstvuyushchuyu oblasti s komandami fajla. Process zatratit na zapusk fajla men'she vremeni, tak kak emu ne pridetsya chi- tat' komandy iz fajlovoj sistemy. Esli komandy fajla vse eshche nahodyatsya v pa- myati, v ih peremeshchenii ne budet neobhodimosti; esli zhe komandy vygruzheny vo vneshnyuyu pamyat', budet gorazdo bystree zagruzit' ih iz vneshnej pamyati, chem iz fajlovoj sistemy (sm. ob etom v glave 9). YAdro udalyaet iz tablicy oblastej zapisi, sootvetstvuyushchie oblastyam s ko- mandami fajla, dlya kotorogo ustanovlen rezhim "sticky-bit" (inymi slovami, kogda oblast' pomechena kak "neot®emlemaya" chast' fajla ili processa), v sle- duyushchih sluchayah: 1. Esli process otkryl fajl dlya zapisi, v rezul'tate sootvetstvuyushchih opera- cij soderzhimoe fajla izmenitsya, pri etom budet zatronuto i soderzhimoe oblasti. 2. Esli process izmenil prava dostupa k fajlu (chmod), otmeniv rezhim "sticky-bit", fajl ne dolzhen ostavat'sya v tablice oblastej. 3. Esli process razorval svyaz' s fajlom (unlink), on ne smozhet bol'she is- polnyat' etot fajl, poskol'ku u fajla ne budet tochki vhoda v fajlovuyu sistemu; sledovatel'no, i vse ostal'nye processy ne budut imet' dostupa k zapisi v tablice oblastej, sootvetstvuyushchej fajlu. Poskol'ku oblast' s komandami fajla bol'she ne ispol'zuetsya, yadro mozhet osvobodit' ee vmeste s ostal'nymi resursami, zanimaemymi fajlom. 4. Esli process demontiruet fajlovuyu sistemu, fajl perestaet byt' dostupnym i ni odin iz processov ne mozhet ego ispolnit'. V ostal'nom - vse kak v predydushchem sluchae. 5. Esli yadro ispol'zovalo uzhe vse prostranstvo vneshnej pamyati, otvedennoe pod vygruzku zadach, ono pytaetsya osvobodit' chast' pamyati za schet oblas- tej, imeyushchih pometku "sticky-bit", no ne ispol'zuemyh v nastoyashchij mo- ment. Nesmotrya na to, chto eti oblasti mogut vskore ponadobit'sya drugim processam, potrebnosti yadra yavlyayutsya bolee srochnymi. V pervyh dvuh sluchayah oblast' komand s pometkoj "sticky-bit" dolzhna byt' osvobozhdena, poskol'ku ona bol'she ne otrazhaet tekushchee sostoyanie fajla. V os- tal'nyh sluchayah eto delaetsya iz prakticheskih soobrazhenij. Konechno zhe yadro osvobozhdaet oblast' tol'ko pri tom uslovii, chto ona ne ispol'zuetsya ni odnim iz vypolnyayushchihsya processov (schetchik ssylok na nee imeet nulevoe znachenie); v protivnom sluchae eto privelo by k avarijnomu zaversheniyu vypolneniya sistemnyh funkcij open, unlink i umount (sluchai 1, 3 i 4, sootvetstvenno). Esli process zapuskaet s pomoshch'yu funkcii exec samogo sebya, algoritm vy- polneniya funkcii neskol'ko uslozhnyaetsya. Po komande sh script komandnyj processor shell porozhdaet novyj process (novuyu vetv'), kotoryj iniciiruet zapusk shell'a (s pomoshch'yu funkcii exec) i ispolnyaet komandy fajla "script". Esli process zapuskaet samogo sebya i pri etom ego oblast' komand dopuskaet sovmestnoe ispol'zovanie, yadru pridetsya sledit' za tem, chtoby pri obrashchenii vetvej processa k indeksam i oblastyam ne voznikali vzaimnye bloki- rovki. Inache govorya, yadro ne mozhet, ne snimaya blokirovki so "staroj" oblasti komand, popytat'sya zablokirovat' "novuyu" oblast', poskol'ku na samom dele eto odna i ta zhe oblast'. Vmesto etogo yadro prosto ostavlyaet "staruyu" ob- 212 last' komand prisoedinennoj k processu, tak kak v lyubom sluchae ej predstoit povtornoe ispol'zovanie. Obychno processy vyzyvayut funkciyu exec posle funkcii fork; takim obrazom, vo vremya vypolneniya funkcii fork process-potomok kopiruet adresnoe prostran- stvo svoego roditelya, no sbrasyvaet ego vo vremya vypolneniya funkcii exec i po sravneniyu s roditelem ispolnyaet obraz uzhe drugoj programmy. Ne bylo by bolee estestvennym ob®edinit' dve sistemnye funkcii v odnu, kotoraya by zag- ruzhala programmu i ispolnyala ee pod vidom novogo processa ? Richi vyskazal predpolozhenie, chto vozniknovenie fork i exec kak otdel'nyh sistemnyh funkcij obyazano tomu, chto pri sozdanii sistemy UNIX funkciya fork byla dobavlena k uzhe sushchestvuyushchemu obrazu yadra sistemy (sm. [Ritchie 84a], str.1584). Odnako, razdelenie fork i exec vazhno i s funkcional'noj tochki zreniya, poskol'ku v etom sluchae processy mogut rabotat' s deskriptorami fajlov standartnogo vvo- da-vyvoda nezavisimo, povyshaya tem samym "elegantnost'" ispol'zovaniya kana- lov. Primer, pokazyvayushchij ispol'zovanie etoj vozmozhnosti, privoditsya v raz- dele 7.8. 7.6 KOD IDENTIFIKACII POLXZOVATELYA PROCESSA YAdro svyazyvaet s processom dva koda identifikacii pol'zovatelya, ne zavi- syashchih ot koda identifikacii processa: real'nyj (dejstvitel'nyj) kod identi- fikacii pol'zovatelya i ispolnitel'nyj kod ili setuid (ot "set user ID" - us- tanovit' kod identifikacii pol'zovatelya, pod kotorym process budet ispol- nyat'sya). Real'nyj kod identificiruet pol'zovatelya, nesushchego otvetstvennost' za vypolnyayushchijsya process. Ispolnitel'nyj kod ispol'zuetsya dlya ustanovki prav sobstvennosti na vnov' sozdavaemye fajly, dlya proverki prav dostupa k fajlu i razresheniya na posylku signalov processam cherez funkciyu kill. Processy mo- gut izmenyat' ispolnitel'nyj kod, zapuskaya s pomoshch'yu funkcii exec programmu setuid ili zapuskaya funkciyu setuid v yavnom vide. Programma setuid predstavlyaet soboj ispolnyaemyj fajl, imeyushchij v pole re- zhima dostupa ustanovlennyj bit setuid. Kogda process zapuskaet programmu setuid na vypolnenie, yadro zapisyvaet v polya, soderzhashchie real'nye kody iden- tifikacii, v tablice processov i v prostranstve processa kod identifikacii vladel'ca fajla. CHtoby kak-to razlichat' eti polya, nazovem odno iz nih, koto- roe hranitsya v tablice processov, sohranennym kodom identifikacii pol'zova- telya. Rassmotrim primer, illyustriruyushchij raznicu v soderzhimom etih polej. Sintaksis vyzova sistemnoj funkcii setuid: setuid(uid) gde uid - novyj kod identifikacii pol'zovatelya. Rezul'tat vypolneniya funkcii zavisit ot tekushchego znacheniya real'nogo koda identifikacii. Esli real'nyj kod identifikacii pol'zovatelya processa, vyzyvayushchego funkciyu, ukazyvaet na su- perpol'zovatelya, yadro zapisyvaet znachenie uid v polya, hranyashchie real'nyj i ispolnitel'nyj kody identifikacii, v tablice processov i v prostranstve pro- cessa. Esli eto ne tak, yadro zapisyvaet uid v kachestve znacheniya ispolnitel'- nogo koda identifikacii v prostranstve processa i to tol'ko v tom sluchae, esli znachenie uid ravno znacheniyu real'nogo koda ili znacheniyu sohranennogo koda. V protivnom sluchae funkciya vozvrashchaet vyzyvayushchemu processu oshibku. Process nasleduet real'nyj i ispolnitel'nyj kody identifikacii u svoego ro- ditelya (v rezul'tate vypolneniya funkcii fork) i sohranyaet ih znacheniya posle vyzova funkcii exec. Na Risunke 7.25 privedena programma, demonstriruyushchaya ispol'zovanie funk- cii setuid. Predpolozhim, chto ispolnyaemyj fajl, poluchennyj v rezul'tate tran- slyacii ishodnogo teksta programmy, imeet vladel'ca s imenem "maury" (kod identifikacii 8319) i ustanovlennyj bit setuid; pravo ego ispolneniya predos- tavleno vsem pol'zovatelyam. Dopustim takzhe, chto pol'zovateli "mjb" (kod identifikacii 5088) i "maury" yavlyayutsya vladel'cami fajlov s temi zhe imenami, kazhdyj iz kotoryh dostupen tol'ko dlya chteniya i tol'ko svoemu vladel'cu. Vo vremya ispolneniya programmy pol'zovatelyu "mjb" vyvoditsya sleduyushchaya informa- 213 ciya: uid 5088 euid 8319 fdmjb -1 fdmaury 3 after setuid(5088): uid 5088 euid 5088 fdmjb 4 fdmaury -1 after setuid(8319): uid 5088 euid 8319 Sistemnye funkcii getuid i geteuid vozvrashchayut znacheniya real'nogo i ispolni- tel'nogo kodov identifikacii pol'zovatelej processa, dlya +------------------------------------------------------------+ | #include | | main() | | { | | int uid,euid,fdmjb,fdmaury; | | | | uid = getuid(); /* poluchit' real'nyj UID */ | | euid = geteuid(); /* poluchit' ispolnitel'nyj UID */| | printf("uid %d euid %d\n",uid,euid); | | | | fdmjb = open("mjb",O_RDONLY); | | fdmaury = open("maury",O_RDONLY); | | printf("fdmjb %d fdmaury %d\n",fdmjb,fdmaury); | | | | setuid(uid); | | printf("after setuid(%d): uid %d euid %d\n",uid, | | getuid(),geteuid()); | | | | fdmjb = open("mjb",O_RDONLY); | | fdmaury = open("maury",O_RDONLY); | | printf("fdmjb %d fdmaury %d\n",fdmjb,fdmaury); | | | | setuid(uid); | | printf("after setuid(%d): uid %d euid %d\n",euid, | | getuid(),geteuid()); | | } | +------------------------------------------------------------+ Risunok 7.25. Primer vypolneniya programmy setuid pol'zovatelya "mjb" eto, sootvetstvenno, 5088 i 8319. Poetomu process ne mo- zhet otkryt' fajl "mjb" (ibo on imeet ispolnitel'nyj kod identifikacii pol'- zovatelya (8319), ne razreshayushchij proizvodit' chtenie fajla), no mozhet otkryt' fajl "maury". Posle vyzova funkcii setuid, v rezul'tate vypolneniya kotoroj v pole ispolnitel'nogo koda identifikacii pol'zovatelya ("mjb") zanositsya zna- chenie real'nogo koda identifikacii, na pechat' vyvodyatsya znacheniya i togo, i drugogo koda identifikacii pol'zovatelya "mjb": oba ravny 5088. Teper' pro- cess mozhet otkryt' fajl "mjb", poskol'ku on ispolnyaetsya pod kodom identifi- kacii pol'zovatelya, imeyushchego pravo na chtenie iz fajla, no ne mozhet otkryt' fajl "maury". Nakonec, posle zaneseniya v pole ispolnitel'nogo koda identifi- kacii znacheniya, sohranennogo funkciej setuid (8319), na pechat' snova vyvo- dyatsya znacheniya 5088 i 8319. My pokazali, takim obrazom, kak s pomoshch'yu prog- rammy setuid process mozhet izmenyat' znachenie koda identifikacii pol'zovate- lya, pod kotorym on ispolnyaetsya. Vo vremya vypolneniya programmy pol'zovatelem "maury" na pechat' vyvoditsya sleduyushchaya informaciya: uid 8319 euid 8319 fdmjb -1 fdmaury 3 after setuid(8319): uid 8319 euid 8319 fdmjb -1 fdmaury 4 214 after setuid(8319): uid 8319 euid 8319 Real'nyj i ispolnitel'nyj kody identifikacii pol'zovatelya vo vremya vypolne- niya programmy ostayutsya ravny 8319: process mozhet otkryt' fajl "maury", no ne mozhet otkryt' fajl "mjb". Ispolnitel'nyj kod, hranyashchijsya v prostranstve pro- cessa, zanesen tuda v rezul'tate poslednego ispolneniya funkcii ili programmy setuid; tol'ko ego znacheniem opredelyayutsya prava dostupa processa k fajlu. S pomoshch'yu funkcii setuid ispolnitel'nomu kodu mozhet byt' prisvoeno znachenie sohranennogo koda (iz tablicy processov), t.e. to znachenie, kotoroe ispolni- tel'nyj kod imel v samom nachale. Primerom programmy, ispol'zuyushchej vyzov sistemnoj funkcii setuid, mozhet sluzhit' programma registracii pol'zovatelej v sisteme (login). Parametrom funkcii setuid pri etom yavlyaetsya kod identifikacii superpol'zovatelya, takim obrazom, programma login ispolnyaetsya pod kodom superpol'zovatelya iz kornya sistemy. Ona zaprashivaet u pol'zovatelya razlichnuyu informaciyu, naprimer, imya i parol', i esli eta informaciya prinimaetsya sistemoj, programma zapuskaet funkciyu setuid, chtoby ustanovit' znacheniya real'nogo i ispolnitel'nogo kodov identifikacii v sootvetstvii s informaciej, postupivshej ot pol'zovatelya (pri etom ispol'zuyutsya dannye fajla "/etc/passwd"). V zaklyuchenie programma login iniciiruet zapusk komandnogo processora shell, kotoryj budet ispolnyat'sya pod ukazannymi pol'zovatel'skimi kodami identifikacii. Primerom setuid-programmy yavlyaetsya programma, realizuyushchaya komandu mkdir. V razdele 5.8 uzhe govorilos' o tom, chto sozdat' katalog mozhet tol'ko pro- cess, vypolnyayushchijsya pod upravleniem superpol'zovatelya. Dlya togo, chtoby pre- dostavit' vozmozhnost' sozdaniya katalogov prostym pol'zovatelyam, komanda mkdir byla vypolnena v vide setuid-programmy, prinadlezhashchej kornyu sistemy i imeyushchej prava superpol'zovatelya. Na vremya ispolneniya komandy mkdir process poluchaet prava superpol'zovatelya, sozdaet katalog, ispol'zuya funkciyu mknod, i predostavlyaet prava sobstvennosti i dostupa k katalogu istinnomu pol'zova- telyu processa. 7.7 IZMENENIE RAZMERA PROCESSA S pomoshch'yu sistemnoj funkcii brk process mozhet uvelichivat' i umen'shat' razmer oblasti dannyh. Sintaksis vyzova funkcii: brk(endds); gde endds - starshij virtual'nyj adres oblasti dannyh processa (adres verhnej granicy). S drugoj storony, pol'zovatel' mozhet obratit'sya k funkcii sleduyu- shchim obrazom: oldendds = sbrk(increment); gde oldendds - tekushchij adres verhnej granicy oblasti, increment - chislo bajt, na kotoroe izmenyaetsya znachenie oldendds v rezul'tate vypolneniya funk- cii. Sbrk - eto imya standartnoj bibliotechnoj podprogrammy na Si, vyzyvayushchej funkciyu brk. Esli razmer oblasti dannyh processa v rezul'tate vypolneniya funkcii uvelichivaetsya, vnov' vydelyaemoe prostranstvo imeet virtual'nye adre- sa, smezhnye s adresami uvelichivaemoj oblasti; takim obrazom, virtual'noe ad- resnoe prostranstvo processa rasshiryaetsya. Pri etom yadro proveryaet, ne prevy- shaet li novyj razmer processa maksimal'no-dopustimoe znachenie, prinyatoe dlya nego v sisteme, a takzhe ne nakladyvaetsya li novaya oblast' dannyh processa na virtual'noe adresnoe prostranstvo, otvedennoe ranee dlya drugih celej (Risu- nok 7.26). Esli vse v poryadke, yadro zapuskaet algoritm growreg, prisoedinyaya k oblasti dannyh vneshnyuyu pamyat' (naprimer, tablicy stranic) i uvelichivaya znachenie polya, opisyvayushchego razmer processa. V sisteme s zameshcheniem stranic yadro takzhe otvodit pod novuyu oblast' prostranstvo osnovnoj pamyati i obnulyaet ego soderzhimoe; esli svobodnoj pamyati net, yadro osvobozhdaet pamyat' putem vygruzki processa (bolee podrobno ob etom my pogovorim v glave 9). Esli s pomoshch'yu funkcii brk process umen'shaet razmer oblasti dannyh, yadro osvobozhda- et chast' ranee vydelennogo adresnogo prostranstva; kogda process popytaetsya obratit'sya k dannym po virtual'nym adresam, prinadlezhashchim osvobozhdennomu 215 prostranstvu, on stolknetsya s oshibkoj adresacii. +------------------------------------------------------------+ | algoritm brk | | vhodnaya informaciya: novyj adres verhnej granicy oblasti | | dannyh | | vyhodnaya informaciya: staryj adres verhnej granicy oblasti | | dannyh | | { | | zablokirovat' oblast' dannyh processa; | | esli (razmer oblasti uvelichivaetsya) | | esli (novyj razmer oblasti imeet nedopustimoe zna-| | chenie) | | { | | snyat' blokirovku s oblasti; | | vernut' (oshibku); | | } | | izmenit' razmer oblasti (algoritm growreg); | | obnulit' soderzhimoe prisoedinyaemogo prostranstva; | | snyat' blokirovku s oblasti dannyh; | | } | +------------------------------------------------------------+ Risunok 7.26. Algoritm vypolneniya funkcii brk Na Risunke 7.27 priveden primer programmy, ispol'zuyushchej funkciyu brk, i vyhodnye dannye, poluchennye v rezul'tate ee progona na mashine AT&T 3B20. Vyzvav funkciyu signal i rasporyadivshis' prinimat' signaly o narushenii segmen- tacii (segmentation violation), process obrashchaetsya k podprogramme sbrk i vy- vodit na pechat' pervonachal'noe znachenie adresa verhnej granicy oblasti dan- nyh. Zatem v cikle, ispol'zuya schetchik simvolov, process zapolnyaet oblast' dannyh do teh por, poka ne obratitsya k adresu, raspolozhennomu za predelami oblasti, tem samym davaya povod dlya signala o narushenii segmentacii. Poluchiv signal, funkciya obrabotki signala vyzyvaet podprogrammu sbrk dlya togo, chtoby prisoedinit' k oblasti dopolnitel'no 256 bajt pamyati; process prodolzhaetsya s tochki preryvaniya, zapolnyaya informaciej vnov' vydelennoe prostranstvo pamyati i t.d. Na mashinah so stranichnoj organizaciej pamyati, takih kak 3B20, nablyu- daetsya interesnyj fenomen. Stranica yavlyaetsya naimen'shej edinicej pamyati, s kotoroj rabotayut mehanizmy apparatnoj zashchity, poetomu apparatnye sredstva ne v sostoyanii ustanovit' oshibku v granichnoj situacii, kogda process pytaetsya zapisat' informaciyu po adresam, prevyshayushchim verhnyuyu granicu oblasti dannyh, no prinadlezhashchim t.n. "polulegal'noj" stranice (stranice, ne polnost'yu zanya- toj oblast'yu dannyh processa). |to vidno iz rezul'tatov vypolneniya program- my, vyvedennyh na pechat' (Risunok 7.27): pervyj raz podprogramma sbrk vozv- rashchaet znachenie 140924, to est' adres, ne dotyagivayushchij 388 bajt do konca stranicy, kotoraya na mashine 3B20 imeet razmer 2 Kbajta. Odnako process polu- chit oshibku tol'ko v tom sluchae, esli obratitsya k sleduyushchej stranice pamyati, to est' k lyubomu adresu, nachinaya s 141312. Funkciya obrabotki signala pribav- lyaet k adresu verhnej granicy oblasti 256, delaya ego ravnym 141180 i, takim obrazom, ostavlyaya ego v predelah tekushchej stranicy. Sledovatel'no, process tut zhe snova poluchit oshibku, vydav na pechat' adres 141312. Ispolniv podprog- rammu sbrk eshche raz, yadro vydelyaet pod dannye processa novuyu stranicu pamyati, tak chto process poluchaet vozmozhnost' adresovat' dopolnitel'no 2 Kbajta pamya- ti, do adresa 143360, dazhe esli verhnyaya granica oblasti raspolagaetsya nizhe. Poluchiv oshibku, process dolzhen budet vosem' raz obratit'sya k podprogramme sbrk, prezhde chem smozhet prodolzhit' vypolnenie osnovnoj programmy. Takim ob- razom, process mozhet inogda vyhodit' za oficial'nuyu verhnyuyu granicu oblasti dannyh, hotya eto i nezhelatel'nyj moment v praktike programmirovaniya. 216 Kogda stek zadachi perepolnyaetsya, yadro avtomaticheski uvelichivaet ego raz- mer, vypolnyaya algoritm, pohozhij na algoritm funkcii brk. Pervonachal'no stek zadachi imeet razmer, dostatochnyj dlya hraneniya parametrov funkcii exec, odna- ko pri vypolnenii processa +-------------------------------------------------------+ | #include | | char *cp; | | int callno; | | | | main() | | { | | char *sbrk(); | | extern catcher(); | | | | signal(SIGSEGV,catcher); | | cp = sbrk(0); | | printf("original brk value %u\n",cp); | | for (;;) | | *cp++ = 1; | | } | | | | catcher(signo); | | int signo; | | { | | callno++; | | printf("caught sig %d %dth call at addr %u\n", | | signo,callno,cp); | | sbrk(256); | | signal(SIGSEGV,catcher); | | } | +-------------------------------------------------------+ +-------------------------------------------+ | original brk value 140924 | | caught sig 11 1th call at addr 141312 | | caught sig 11 2th call at addr 141312 | | caught sig 11 3th call at addr 143360 | | ...(tot zhe adres pechataetsya do 10-go | | vyzova podprogrammy sbrk) | | caught sig 11 10th call at addr 143360 | | caught sig 11 11th call at addr 145408 | | ...(tot zhe adres pechataetsya do 18-go | | vyzova podprogrammy sbrk) | | caught sig 11 18th call at addr 145408 | | caught sig 11 19th call at addr 145408 | | - | | - | +-------------------------------------------+ Risunok 7.27. Primer programmy, ispol'zuyushchej funkciyu brk, i rezul'taty ee kontrol'nogo progona etot stek mozhet perepolnit'sya. Perepolnenie steka privodit k oshibke adresa- cii, svidetel'stvuyushchej o popytke processa obratit'sya k yachejke pamyati za pre- delami otvedennogo adresnogo prostranstva. YAdro ustanavlivaet prichinu voz- niknoveniya oshibki, sravnivaya tekushchee znachenie ukazatelya vershiny steka s raz- merom oblasti steka. Pri rasshirenii oblasti steka yadro ispol'zuet tochno ta- koj zhe mehanizm, chto i dlya oblasti dannyh. Na vyhode iz preryvaniya process 217 +------------------------------------------------------------+ | /* chtenie komandnoj stroki do simvola konca fajla */ | | while (read(stdin,buffer,numchars)) | | { | | /* sintaksicheskij razbor komandnoj stroki */ | | if (/* komandnaya stroka soderzhit & */) | | amper = 1; | | else | | amper = 0; | | /* dlya komand, ne yavlyayushchihsya konstrukciyami komandnogo | | yazyka shell */ | | if (fork() == 0) | | { | | /* pereadresaciya vvoda-vyvoda ? */ | | if (/* pereadresaciya vyvoda */) | | { | | fd = creat(newfile,fmask); | | close(stdout); | | dup(fd); | | close(fd); | | /* stdout teper' pereadresovan */ | | } | | if (/* ispol'zuyutsya kanaly */) | | { | | pipe(fildes); | | | +------------------------------------------------------------+ Risunok 7.28. Osnovnoj cikl programmy shell imeet oblast' steka neobhodimogo dlya prodolzheniya raboty razmera. 7.8 KOMANDNYJ PROCESSOR SHELL Teper' u nas est' dostatochno materiala, chtoby perejti k ob®yasneniyu prin- cipov raboty komandnogo processora shell. Sam komandnyj processor namnogo slozhnee, chem to, chto my o nem zdes' budem izlagat', odnako vzaimodejstvie processov my uzhe mozhem rassmotret' na primere real'noj programmy. Na Risunke 7.28 priveden fragment osnovnogo cikla programmy shell, demonstriruyushchij asinhronnoe vypolnenie processov, perenaznachenie vyvoda i ispol'zovanie ka- nalov. Shell schityvaet komandnuyu stroku iz fajla standartnogo vvoda i interpre- tiruet ee v sootvetstvii s ustanovlennym naborom pravil. Deskriptory fajlov standartnogo vvoda i standartnogo vyvoda, ispol'zuemye registracionnym shell'om, kak pravilo, ukazyvayut na terminal, s kotorogo pol'zovatel' regis- triruetsya v sisteme (sm. glavu 10). Esli shell uznaet vo vvedennoj stroke konstrukciyu sobstvennogo komandnogo yazyka (naprimer, odnu iz komand cd, for, while i t.p.), on ispolnyaet komandu svoimi silami, ne pribegaya k sozdaniyu novyh processov; v protivnom sluchae komanda interpretiruetsya kak imya ispol- nyaemogo fajla. Komandnye stroki prostejshego vida soderzhat imya programmy i neskol'ko pa- rametrov, naprimer: who grep -n include *.c ls -l 218 +------------------------------------------------------------+ | if (fork() == 0) | | { | | /* pervaya komponenta komandnoj stroki */| | close(stdout); | | dup(fildes[1]); | | close(fildes[1]); | | close(fildes[0]); | | /* standartnyj vyvod napravlyaetsya v ka- | | nal */ | | /* komandu ispolnyaet porozhdennyj pro- | | cess */ | | execlp(command1,command1,0); | | } | | /* vtoraya komponenta komandnoj stroki */ | | close(stdin); | | dup(fildes[0]); | | close(fildes[0]); | | close(fildes[1]); | | /* standartnyj vvod budet proizvodit'sya iz| | kanala */ | | } | | execve(command2,command2,0); | | } | | /* s etogo mesta prodolzhaetsya vypolnenie roditel'skogo | | * processa... | | * process-roditel' zhdet zaversheniya vypolneniya potomka,| | * esli eto vytekaet iz vvedennoj stroki | | * / | | if (amper == 0) | | retid = wait(&status); | | } | +------------------------------------------------------------+ Risunok 7.28. Osnovnoj cikl programmy shell (prodolzhenie) Shell "vetvitsya" (fork) i porozhdaet novyj process, kotoryj i zapuskaet prog- rammu, ukazannuyu pol'zovatelem v komandnoj stroke. Roditel'skij process (shell) dozhidaetsya zaversheniya potomka i povtoryaet cikl schityvaniya sleduyushchej komandy. Esli process zapuskaetsya asinhronno (na fone osnovnoj programmy), kak v sleduyushchem primere nroff -mm bigdocument & shell analiziruet nalichie simvola ampersand (&) i zanosit rezul'tat proverki vo vnutrennyuyu peremennuyu amper. V konce osnovnogo cikla shell obrashchaetsya k etoj peremennoj i, esli obnaruzhivaet v nej priznak nalichiya simvola, ne vy- polnyaet funkciyu wait, a tut zhe povtoryaet cikl schityvaniya sleduyushchej komandy. Iz risunka vidno, chto process-potomok po zavershenii funkcii fork polucha- et dostup k komandnoj stroke, prinyatoj shell'om. Dlya togo, chtoby pereadreso- vat' standartnyj vyvod v fajl, kak v sleduyushchem primere nroff -mm bigdocument > output process-potomok sozdaet fajl vyvoda s ukazannym v komandnoj stroke imenem; 219 esli fajl ne udaetsya sozdat' (naprimer, ne razreshen dostup k katalogu), pro- cess-potomok tut zhe zavershaetsya. V protivnom sluchae process-potomok zakryva- et staryj fajl standartnogo vyvoda i perenaznachaet s pomoshch'yu funkcii dup deskriptor etogo fajla novomu fajlu. Staryj deskriptor sozdannogo fajla zak- ryvaetsya i sohranyaetsya dlya zapuskaemoj programmy. Podobnym zhe obrazom shell perenaznachaet i standartnyj vvod i standartnyj vyvod oshibok. +-----------+ | Shell | +-----+-----+ wait | ^ | | +-----+-----+ exit | wc | +-----+-----+ read | ^ | | +-----+-----+ write | ls - l | +-----------+ Risunok 7.29. Vzaimosvyaz' mezhdu processami, ispolnyayushchimi ko- mandnuyu stroku ls -l|wc Iz privedennogo teksta programmy vidno, kak shell obrabatyvaet komandnuyu stroku, ispol'zuya odin kanal. Dopustim, chto komandnaya stroka imeet vid: ls -l|wc Posle sozdaniya roditel'skim processom novogo processa process-potomok sozda- et kanal. Zatem process-potomok sozdaet svoe otvetvlenie; on i ego potomok obrabatyvayut po odnoj komponente komandnoj stroki. "Vnuchatyj" process ispol- nyaet pervuyu komponentu stroki (ls): on sobiraetsya vesti zapis' v kanal, poe- tomu on zakryvaet staryj fajl standartnogo vyvoda, peredaet ego deskriptor kanalu i zakryvaet staryj deskriptor zapisi v kanal, v kotorom (v deskripto- re) uzhe net neobhodimosti. Roditel' (wc) "vnuchatogo" processa (ls) yavlyaetsya potomkom osnovnogo processa, realizuyushchego programmu shell'a (sm. Risunok 7.29). |tot process (wc) zakryvaet svoj fajl standartnogo vvoda i peredaet ego deskriptor kanalu, v rezul'tate chego kanal stanovitsya fajlom standartno- go vvoda. Zatem zakryvaetsya staryj i uzhe ne nuzhnyj deskriptor chteniya iz ka- nala i ispolnyaetsya vtoraya komponenta komandnoj stroki. Oba porozhdennyh pro- cessa vypolnyayutsya asinhronno, prichem vyhod odnogo processa postupaet na vhod drugogo. Tem vremenem osnovnoj process dozhidaetsya zaversheniya svoego potomka (wc), posle chego prodolzhaet svoyu obychnuyu rabotu: po zavershenii processa, vy- polnyayushchego komandu wc, vsya komandnaya stroka yavlyaetsya obrabotannoj. Shell vozvrashchaetsya v cikl i schityvaet sleduyushchuyu komandnuyu stroku. 7.9 ZAGRUZKA SISTEMY I NACHALXNYJ PROCESS Dlya togo, chtoby perevesti sistemu iz neaktivnoe sostoyanie v aktivnoe, administrator vypolnyaet proceduru "nachal'noj zagruzki". Na raznyh mashinah eta procedura imeet svoi osobennosti, odnako vo vseh sluchayah ona realizuet odnu i tu zhe cel': zagruzit' kopiyu operacionnoj sistemy v osnovnuyu pamyat' mashiny i zapustit' ee na ispolnenie. Obychno procedura nachal'noj zagruzki vklyuchaet v sebya neskol'ko etapov. Pereklyucheniem klavish na pul'te mashiny ad- ministrator mozhet ukazat' adres special'noj programmy apparatnoj zagruzki, a mozhet, nazhav tol'ko odnu klavishu, dat' komandu mashine zapustit' proceduru zagruzki, ispolnennuyu v vide mikroprogrammy. |ta programma mozhet sostoyat' iz neskol'kih komand, podgotavlivayushchih zapusk drugoj programmy. V sisteme UNIX 220 procedura nachal'noj zagruzki zakanchivaetsya schityvaniem s diska v pamyat' blo- ka nachal'noj zagruzki (nulevogo bloka). Programma, soderzhashchayasya v etom blo- ke, zagruzhaet iz fajlovoj sistemy yadro OS (naprimer, iz fajla s imenem "/unix" ili s drugim imenem, ukazannym administratorom). Posle zagruzki yadra sistemy v pamyat' upravlenie peredaetsya po startovomu adresu yadra i yadro za- puskaetsya na vypolnenie (algoritm start, Risunok 7.30). YAdro inicializiruet svoi vnutrennie struktury dannyh. Sredi prochih struktur yadro sozdaet svyaznye spiski svobodnyh buferov i indeksov, hesh-oche- redi dlya buferov i indeksov, inicializiruet struktury oblastej, tochki vhoda v tablicy stranic i t.d. Po okonchanii etoj fazy yadro montiruet kornevuyu faj- lovuyu sistemu i formiruet sredu vypolneniya nulevogo processa, sredi vsego prochego sozdavaya prostranstvo processa, inicializiruya nulevuyu tochku vhoda v tablice processa i delaya kornevoj katalog tekushchim dlya processa. Kogda formirovanie sredy vypolneniya processa zakanchivaetsya, sistema is- polnyaetsya uzhe v vide nulevogo processa. Nulevoj process "vetvitsya", zapuskaya algoritm fork pryamo iz yadra, poskol'ku sam process ispolnyaetsya v rezhime yad- +------------------------------------------------------------+ | algoritm start /* procedura nachal'noj zagruzki sistemy */| | vhodnaya informaciya: otsutstvuet | | vyhodnaya informaciya: otsutstvuet | | { | | proinicializirovat' vse struktury dannyh yadra; | | psevdo-montirovanie kornya; | | sformirovat' sredu vypolneniya processa 0; | | sozdat' process 1; | | { | | /* process 1 */ | | vydelit' oblast'; | | podklyuchit' oblast' k adresnomu prostranstvu processa| | init; | | uvelichit' razmer oblasti dlya kopirovaniya v nee is- | | polnyaemogo koda; | | skopirovat' iz prostranstva yadra v adresnoe prost- | | ranstvo processa kod programmy, ispolnyaemoj proces-| | som; | | izmenit' rezhim vypolneniya: vernut'sya iz rezhima yadra | | v rezhim zadachi; | | /* process init dalee vypolnyaetsya samostoyatel'no -- | | * v rezul'tate vyhoda v rezhim zadachi, | | * init ispolnyaet fajl "/etc/init" i stanovitsya | | * "obychnym" pol'zovatel'skim processom, proizvodya- | | * shchim obrashcheniya k sistemnym funkciyam | | */ | | } | | /* prodolzhenie nulevogo processa */ | | porodit' processy yadra; | | /* nulevoj process zapuskaet programmu podkachki, uprav- | | * lyayushchuyu raspredeleniem adresnogo prostranstva proces- | | * sov mezhdu osnovnoj pamyat'yu i ustrojstvami vygruzki. | | * |to beskonechnyj cikl; nulevoj process obychno priosta-| | * navlivaet svoyu rabotu, esli neobhodimosti v nem bol'-| | * she net. | | */ | | ispolnit' programmu, realizuyushchuyu algoritm podkachki; | | } | +------------------------------------------------------------+ Risunok 7.30. Algor