A Linux - a DOS-tól eltérõen - valódi többfeladatos (multitask) operációs
rendszer. Kihasználva az Intel 80386 processzor nyújtotta fejlett tár és
taszkkezelési lehetõségeket, valódi idõosztásos környezetet biztosít.
A 386-os processzor többféle üzemmódjai közül a Linux a "supervisor"
üzemmódot használja a kernel, az operációs rendszer mag futtatására,
ebben az üzemmódban a kernelnek hozzáférése van a gép összes fizikai
erõforrásához, a felhasználói folyamatok (processzek) pedig ún. "user"
üzemmódban futnak. A 386-os processzoron lehetõség
van több, egymástól független "user" módú ún. taszk definiálására,
amelyek
egymástól védettek, nem tudják egymás és a felügyelõ kernel memória-
területét kiolvasni vagy módosítani, és a gép közvetlen hardver
erõforrásaihoz sincs hozzáférésük (a valóságban ez úgy mûködik,
hogy "user" módban csak a processzor utasításkészletének egy része
hajtható végre, nem megengedett utasítás végrehajtásának kísérletekor
vagy nem megendegett memóriacímre hivatkozáskor a vezérlés hibaüzenettel
visszakerül a supervisor módban futó felügyelõ programhoz, vagyis a
kernelhez). Így biztosítható az egyes felhasználói programok egymástól
való védelme. Mivel az egyes folyamatoknak a gép fizikai erõforrásaihoz
(pl. winchester, képernyõ) sincs közvetlen hozzáférésük, bármilyen
perifériamûveletet csak a kernel meghívása útján végezhetnek, így
mód nyílik peldául biztonságos file-rendszer megvalósítására is.
Nincs az a trükk, amivel az egyik felhasználó el tudna olvasni olyan
adatot, amihez nincs engedélyezett hozzáférése - amennyiben persze a
biztonsági rendszerben nincsenek programozói hibák és a rendszer
konfigurációja megfelelõ. Az emberi gyarlóságot nem tekintve a Linux
biztonságos többfelhasználós operációs rendszernek tekinthetõ.
A kernel teljes mértékben, fizikai szinten hozzáfér a gép erõforrásaihoz.
Fizikai, a lehetõ legalacsonyabb szinten kezeli is a hardvert, a legnagyobb
teljesítmény elérése érdekében. A boot-olást (rendszer betöltést)
kivéve egyáltalán nem használja a BIOS-t: ennek oka, hogy a BIOS programja
a DOS figyelembevételével készült, és nem alkalmas multitaszk operációs
rendszer futtatására.
Memóriakezelésében szintén kihasználja a 386 által nyújtott
lehetõségeket: lapozásos virtuális memóriakezelést használ, ahol a
fizikai memóriát kiegészíthetjük a winchesterrõl vett virtuális
memóriával (page vagy swap terület). A teljes memóriát lapokra osztja,
ezen virtuális lapokat rendeli hozzá az egyes folyamatokhoz, és gondoskodik
róla, hogy az éppen szükséges lapok a fizikai memóriában legyenek.
Itt kell megemlíteni, hogy a Linux használja a virtuális tárkezelés
mindkét (gyakran összekevert) fajtáját, a lapozást (paging) és a
tárcserét (swapping) is. Lapozásnál folyamatoktól függetlenül, a rendszer
arra ügyel, hogy a szükséges lapok a fizikai memóriában legyenek,
ha azok esetleg diszken vannak, akkor gondoskodik memóriába olvasásukról,
illetve a ha a fizikai memória teli van, akkor a ritkábban használt
lapokat a diszkre írja. Tárcserénél pedig a rendszer figyelemmel kíséri
az egyes folyamatok aktivitását is, es ha szabad memóriára van szükség,
egy inaktív folyamat egészét háttértárra írja, felszabadítva ezzel
a folyamat által használt összes fizikai memóriát. A Linux a két
módszer keverékét használja: amíg bõvében van a memóriának, csak
egyes lapokat lapoz ki/be, de például ha úgy látja, hogy egy folyamat
hosszú ideje inaktív, és nem csak egy-két lapnyi memóriára van szükség,
akkor az adott folyamathoz tartozó összes fizikai lapot diszkre menti.
Szorosan kapcsolódik a memória-lapkezelés mechanizmusához a Linux
buffer cache kezelési módszere: a buffer cache a Unix rendszerek diszk-
eléréshez használt gyorsítótárja, amelyet a kernel kezel, mivel minden
folyamat csak és kizárólag a kernel meghívásával végezhet
diszkmûveletet. Linuxban a buffer cache mérete dinamikusan, a rendszer-
terheléstõl függõen változik: mindig az éppen szabad fizikai memória
egészét erre a célra használja. A diszk-irások is a buffer cache-n
keresztül történnek: minden írás elõször a cache memóriába kerül,
és vagy egy megadott idõ elteltével iródik ki diszkre, vagy pedig akkor,
ha a rendszer számára "elegendõ" kiírnivaló összegyûlt.
Ezért fontos az, hogy a megfelelõ shutdown procedúra (a rendszer
"lelövése", leállítása) végrehajtása nélkül soha ne kapcsoljuk ki
a gépet: kikapcsolás elõtt mindig szükséges a diszk tartalmának
szinkronizálása a memóriában lévõ állapottal, a nyitott file-ok
lezárása - ezen lépések elmulasztása esetén kikapcsoláskor a diszk
tartalma helytelen lehet, információk, egész file-ok veszhetnek el.
Ugyanez történhet persze áramszünet vagy más hiba esetén is: ez az az
ár, amit a Unix filerendszer által nyújtott nagyobb teljesítményért
fizetnünk kell. A Unix-ok általában (így a Linux is) rendelkeznek
funkciókkal az esetleges információvesztés minimalizálására, illetve
a korrekt file-rendszer visszaállítására - tulajdonképpen egy átlagos
Linux rendszerben váratlan rendszerösszeomláskor maximum csak a legutóbbi
30 másodperc munkája veszhet el - nagyon kicsi valószínûségû extrém
esetektõl eltekintve. De az ilyen adatvesztés veszélye minden, a diszk-
írást bufferelõ rendszerben fennáll.
A fejlett memóriakezelés lehetõvé teszi további, a teljesítményt
növelõ megoldások használatát is: ezek egyike az ún. "demand paging",
ami azt jelenti, hogy egy futtatható file végrahatjtásakor nem az egész
file töltõdik be a memóriába, hanem mindig csak azok a lapjai, amelyekre
a végrehajtás során éppen szükség van: gondoljunk csak bele, minden
programnak vannak olyan részei (inicializálás, hibakezelõ részek),
amelyek csak egyszer, vagy éppenséggel egyszer sem futnak le - ezeket aztán
vagy soha be sem tölti a rendszer a memóriába, vagy pedig miután lefutottak,
rögtön fel is szabadítja az általuk elfoglalt területet.
Többfeladatos mûködés esetén, amikor egyszerre több program tartózkodik
a fizikai memóriában, hasznos a Linuxban szintén használt "osztott
könyvtár" (shared library) mechanizmus, vagy más néven a dinamikus
(futásidejû) programösszefûzés (link). Alapötlete az, hogy mivel mindegyik
program C-ben iródott és ugyanabban a környezetben fordult le, ezért
valószínûleg lesz egy csomó olyan függvény (például a
képernyõkezelõ könyvtári függvények) amelyeknek kódja minden programban
ugyanaz, és felesleges minden programmal együtt a memóriába tölteni
õket, elég csak egyszer - csak a programok tudják, hol keressék a
memóriában ezeket a függvényeket. Így minden programba elég egy "csonk"-
nak (stub) nevezett programrészlet beépítése, amelyik a dinamikus linker
segítségével gondoskodik a megfelelõ függvény megtalálásáról illetve
memóriába töltésérõl, amennyiben az még nem lenne betöltve.
Még egy memóriakezelési finomság van, amelyet Unix rendszerekben
elõszeretettel használnak: ez pedig az úgynevezett copy-on-write (irásnál
másold) mechanizmus, amely a következõképpen mûködik: multitaszkos
operációs rendszerben gyakran lehet arra szükség, hogy bizonyos memória-
lapokat több folyamat között megosszunk, vagy a legtipikusabb példa:
Unix-ban új folyamat létrehozása mindig egy másik folyamat memóriájának
lemásolásával történik. Mivel viszont egy memórialapra "többfelõl",
több folyamat memóriatérképébõl tudunk hivatkozni, nem is kell azt a
lapot lemásolni, csak elhelyezni az ugyanarra a lapra mutató hivatkozásokat
a megfelelõ helyeken. Mivel a memóriamásolás meglehetõsen idõigényes
dolog, ezzel kritikus helyen (a felhasználó szemszögébõl holtidõnek
számító folyamat-létrehozáskor) sok idõt takaríhatunk meg, és most
már csak arra kell vigyáznunk, hogy ha az ugyanarra a lapra hivatkozó több
folyamat közül valamelyik módosítani akarja a lapot, (mivel mindegyik
folyamat azt hiszi, a memórialap csak az övé) akkor készítsünk csak
annak a folyamatnak a számára másolatot, amelyet aztán módosíthat
kedve szerint.
Mivel egy processzoron kell konkurrensen több feladatot végrehajtania, az
operációs rendszernek, ezért valamilyen formában meg kell osztania a
rendelekzése álló CPU idõt az egyes folyamatok között. A Unix rendszerek
(így a Linux is) a preemptív idõosztásos ütemezés módszerét
alkalmazzák, ami azt jelenti, hogy a rendelkezésre álló idõt felosztja
egyenlõ részekre, és ezekbõl az egyenlõ idõszeletekbõl juttat -
a folyamat prioritásának megfelelõen - többet vagy kevesebbet az adott
folyamatnak. Az egyes folyamatok prioritása természetesen állítható.
Az ütemezés preemptív volta annyit jelent, hogy amikor az adott folyamat
számára kijelölt idõszelet letelt, a kernel megszakítja a folyamat
futását és más folyamatnak adja át a vezérlést - nincs tehát mód
arra, hogy egy folyamat a végtelenségig magánál tartsa a vezérlést,
és megakadályozza a többi folyamat futását. Linuxban az ütemezés
alapegysége az 1/100 másodperc.
Nem szabad azonban egy fontos dologról megfeledkeznünk: A Unix nem valós-
idejû (real-time) operációs rendszer, ami annyit jelent, hogy ha több
folyamat fut egyszerre, és az egyiktõl elkerül a vezérlés, akkor
valamekkora (rendszerint nagyon rövid) idõ múlva vissza is fogja
majd kapni - a két aktív (futó) állapot közti idõre azonban nincs
szigorú felsõ korlát. Az esetek 99.9999999 százalékában ez az idõ
(még egy leterhelt - de nem indokolatlanul túlterhelt rendszeren is) pár
tized másodperc - azonban soha nem mondhatjuk, hogy biztosan csak ennyi.
Ezt a tényt pontos és rövid idõzítéseket használó programoknál nem
árt szem elõtt tartani.
A Linux, eltérõen a PC-n eddig megszokott operációs rendszerektõl, nem
csak többfeladatos, ahol egy felhasználó egyidejûleg több programot
futtathat (mint például a MS-Windows és az OS/2), hanem többfelhasználós
is, vagyis egyidejûleg több felhasználó használhatja ugyanazt a rendszert,
és mindegyikük akár több programot is futtathat. Ennek megvalósításához
azonban szükség van néhány új fogalom, koncepció bevezetésére:
Rögtön elsõ problémaként jelentkezik az, hogy egy PC-nek csak egy
billentyûzete, és (kevés kivételtõl eltekintve) csak egy monitora van, amit
értelemszerûen egyszerre csak egyvalaki használhat. A Unix filozófia minden
egyes bejelentkezett felhasználóhoz hozzárendel egy egy úgynevezett
terminált: egy terminál pedig egy billentyûzet + megjelenítõ egység
(leggyakrabban szöveges display) együttesét jelenti. Az adott Unixos géphez
legközvetlenebbül csatolt terminált (Linux esetén a gép saját
billentyûzetét és monitorát) konzol terminálnak (console terminal)
nevezzük, ez abból a szempontból kitüntett, hogy bizonyos
rendszeradminisztrációs feladatok csak innét hajthatók végre. További
terminálok csatolhatók még a géphez soros vonalon (ez a legõsibb Unixos
megoldás, egy terminálemulációs szoftver és egy soros kábel
segítségével akár kidobandó XT-inket is egyszerûen soros terminállá
alakíthatjuk, illetve direkt erre a célra készült terminálokhoz manapság
már fillérekért hozzájuthatunk). De köthetünk soros vonalra modemet is:
ekkor a felhasználói terminál a telefonvonal "túlsó végén" lesz,
távolról is elérhetõvé téve rendszerünket.
A hálózaton vagy grafikus felületen keresztül bejelentkezett
felhasználókhoz ún. pszeudo-terminálokat rendel a rendszer, ahol is a
billentyûzet és a képernyõ annak a gépnek a billentyûzetéhez és
képernyõjéhez rendelõdik, amely elõtt a felhasználó ül. A terminálok
megnevezése a szakzsargonban tty (angolul betûzve ejtik), illetve a
pszeudo-termináloké pty vagy ttyp, a Linux ez utóbbi megnevezést használja.
Minden Unix rendszer többféle, képességeik alapján osztályozható
terminált képes kezelni: mivel nem alakult ki egységes szabvány, és a
nagygépek hõskorában sokféle gyártó sokféle terminált gyártott, ezért
a Unix rendszereket általában felkészítik a sornyomtató tipusú,
sorüzemmódú, kurzor-címzésre nem képes termináloktól kezdve a modernebb,
színkezelésre és akár ANSI grafikára képes terminálokig bezárólag
sokféle termináltípus kezelésére. Az egyes
terminálokat gyártó és típusra utaló megnevezéssel azonosítják:
Amennyiben csak kozolról használjuk gépünket, elég annyit tudni hogy a
konzol terminál azonosítója "console".
Az egyes felhasználók azonosítására a "login név" (account, témaszám)
rendszert használja a Unix: minden felhasználónak van egy (maximum 8
karakter hosszú, konvenció szerint kisbetûvel irott) azonosítója, és
ehhez tartozik a maximum 8-16 karakter hosszú jelszó. A finomabb
hozzáférés hierarchia kialakítása érdekében a felhasználókat
csoportokba (groups) oszthatjuk: minden felhasználónak van egy elsõdleges
csoportja (pl. student), és ezen kívül tartozhat még más csoportokhoz is
(pl. texusers). A csoportneveket is konvenció szerint kisbetûvel írják.
Belsõleg a rendszer minden egyes felhasználóhoz az egyedi felhasználó-
néven kívul még egy numerikus felhasználó és (esetleg több) csoport-
azonosítót rendel (UID - user identification és GID - group identification).
Léteznek kitüntetett felhasználónevek is, illetve legalább egy, amelyik
minden rendszeren megvan: ez a "root" felhasználó, a rendszergazda
azonosítója, aki felelõs az adott rendszer karbantartásáért és
üzemeltetéséért, és akinek a rendszeren "mindent szabad": õ az, akinek
a rendszer egészéhez hozzáférése van. Fel kell itt hívni a figyelmet
egy kialakult, de elkerülendõ rossz gyakorlatra: sokan, akik csak egyedül
használják Linuxos gépüket, minden tevékenységüket "root" hozzáférési
jogokkal végzik, mondván, hogy így jobban hozzáférnek a rendszerhez, nem
kell mindenféle korlátozásokkal veszõdniük. Nem érdemes ezt a gyakorlatot
folytatni, mert egy jól bekonfigurált rendszerben normál (nem privilegizált)
felhasználókent is kényelmesen elérhetünk minden szolgáltatást, amire
hétköznapi felhasználás során szükségünk lehet - viszont
figyelmetlenséggel vagy elgépeléssel sokkal kisebb kárt tudunk okozni. Egy
root jogokkal kiadott hibás vagy át nem gondolt utasítás egy pillanat
alatt az egész rendszerünket jóvátehetetlenül tönkreteheti.
Megjegyzendõ még, hogy "root"-tal ekvivalens felhasználót akár többet
is hozhatunk létre, az összes olyan felhasználó, akinek UID-je 0
(felhasználó létrehozásakor ezt megadhatjuk) root-tal ekvivalens lesz, de
általában nem érdemes ezt tennünk: egy rendszeren éppen elég egy
darab teljhatalmú felhasználó.
Mielõtt továbblépnénk, feltétlenül szükséges megismerkednünk még egy,
az egész rendszert átható szervezõ elvvel: ez pedig a file koncepció.
Unixban ugyanis (túlzás nélkül) az égvilágon minden file. Definíció
szerint (kissé tudományosan) a file olyan "kommunikációs végpont",
ahova vagy byte-folyamot (byte stream) tudunk írni, vagy byte-folyamot
tudunk onnét olvasni (esetleg mindkettõt). Fileként kezelhetõ tehát
a billentyûzet (csak olvasható), a szöveges képernyõ (csak írható), a
nyomtató, de még a fizikai memória tartalma is (!). A gépben lévõ
winchester szektorait (ha nem csak egyes file-okat akarunk elérni) is
egy speciális file olvasásával illetve irásával érhetjük el, ugyanígy
az hálózati eszközöket is a file-kezelés szabályainak megfelelõen
használhatjuk. Ez utóbbi három esetben persze szükség van a megfelelõ
jogosultságokra: a fizikai memória tartalmát vagy direktben a winchester
szektorait "mezei" felhasználó nem láthatja.
Ezt a file-orientált szervezésmódot (amely tulajdonképpen egy Unix rendszer
fõ szervezõ ereje) folyamatosan érdemes észben tartanunk: ha egyszer
kellõen átláttuk logikáját, sok addig bonyolultnak, lehetetlennek tartott
mûvelet roppant egyszerûvé válik.
A Unix file rendszere a DOS-hoz hasonló könyvtár rendszerû (helyesebben
szólva a DOS hasonlít a Unixhoz), azzal a különbséggel, hogy itt
nincsenek különbözõ meghajtók, hanem a rendszerben lévõ minden file-t
egy gyökérkönyvtárból kiindulva (ennek jelölése / könyvtár)
elérhetünk. Fontos külõnbség még, hogy a Unix file-nevek nem a DOS-ból
ismert 8+3 szabály szerint formálódnak: egy file-név maximum 255 karakter
hosszú lehet, és tetszõleges karaktert tartalmazhat (vigyázat, tartalmazhat
nem nyomtatható, nem gépelhetõ karaketereket is! Gonoszul elnevezett file-
okkal sok bosszúságot okozhatunk magunknak és felhasználótársainknak.)
Fontos külõnbség továbbá, hogy a Unix (nem csak file-nevekben, mindenhol)
különbséget tesz kis- és nagybetû között (case sensitive). Az ALMA,
Alma,alma,almA tehat mind-mind különbözõ file-okat jelentenek. Mivel
file-névben pont is lehet, ezért Unixban is adhatunk kiterjesztéseket file-
oknak: ezek azonban a rendszer számára semmilyen jelentéssel nem bírnak:
csak a felhasználók eligazodását segíti elõ, ha betartjuk a megfelelõ
file-nevezési konvenciókat. Azt sem a file-névbõl tudja meg a rendszer,
hogy például az adott file futtatható-e vagy sem: a következõ részben
látni fogjuk, mibõl is derül ez ki. Elõtte azonban még egy fontos dolgot
tisztáznunk kell: hogyan valósul meg az, hogy a gépben több fizikai
eszköz van (floppy, esetleg több winchester) és mégis az összes file-ot
egy könyvtárstruktúrában látjuk ? Úgy történik, hogy van egy
kitüntetett diszk (vagy partíció, esetleg ramdisk) amelyen a gyökér
könyvtár ( / könyvtár) található, és a többi úgynevezett filesystem-et
(filesystem-nek Unix alatt az egy diszken,partíción, egy rendszerbe szervezett
file-ok összességét nevezzük) pedig a file-rendszer valamely
alkönyvtárába lehet beilleszteni (mounting, igazán jó magyar terminológia
mindezidáig nem született rá). Tehát ha van például egy /mnt/floppy
alkönyvtárunk a rendszerben, es van egy floppy diszkünk, amelyen lévõ
filesystem-ben a /alma, /narancs és a /alma/starking könyvtárak vagy file-ok
vannak, akkor a floppy "felmount-olása" után a /mnt/floppy/alma,
/mnt/floppy/narancs és a /mnt/floppy/alma/starking könyvtárakat vagy file-
okat fogjuk látni. Láttuk azt is, hogy Unixban az egyes könyvtárak
szeparálására a DOS \ (backslash) karakterével ellentétben a / -t (slash)
használják. Nem érdemes eltéveszteni, mert amint késõbb látni fogjuk,
a backslash karakternek is megvan a saját szerepe.
Unixban kétféleképpen adhatunk meg file elérési útvonalat, ez hasonlít
a DOS-nál megszokottra: abszolút módon, a gyökérkönyvtárból indulva,
amikor az elérési út neve / -rel kezdõdik, vagy relatív módon, például
../../alma/starking, ami azt jelenti, hogy az aktuális könyvtárból
lépjünk felfelé kettõt, és onnét lépjünk az alma könyvtárba, ha a
starking-ot akarjuk megtalálni.
A Linux képes arra, hogy többféle fizikai és logikai szervezésû
filesystem-et egy könyvtárszerkezetben kezeljen: támogatja többféle Unix-os
filesystem formátum mellett a DOS FAT filerendszert, tudja olvasni az OS/2
HPFS file-okat, ismeri a CD-s fileformátumokat, és tudja kezelni a TCP/IP
hálózat felett mûködõ hálózati file-rendszert az NFS-t is.
Még két Unix-os specialitásról kell beszélnünk: az egyik az, hogy abból
hogy /mnt/floppy/narancs, nem derül ki, hogy ez a narancs egy könyvtár-e
vagy egy file - ennek eldöntéséhez a file neve egyedül nem elég.
A másik specialitás ismertetéséhez kicsit jobban bele fogunk mászni
a Unix filerendszerek rejtelmeibe. A tárgyalt sajátosság a "link", az a
tulajdonság, hogy egy file-nak egyszerre több neve is lehet: több néven
is tudunk ugyanarra a file-ra hivatkozni (pl. megcsinálhatjuk, hogy a
/gyumolcs/alma és a /holnap/reggeli file-nevek fizikailag ugyanarra a file-ra
mutassanak). Ez pedig úgy lehetséges, hogy egy Unix filesystem-ben minden
egyes file-hoz tartozik egy inode -nak nevezett rekord, amely tartalmazza
a file nevét, létrehozásának dátumát és minden egyéb, a file-lal
kapcsolatos adatot, kivéve a file tartalmát - többek között azt az
információt is, hogy fizikailag a diszk melyik szektorában kezdõdik az a
file. Létrehozhatunk egy újabb inode-ot, amelyben a file neve más, de
a kezdõ szektor száma azonos: és máris két helyrõl hivatkozhatunk
ugyanarra a file-ra. Törléskor pedig mindaddig csak az inode-okat töroljük,
amíg el nem érünk az utolsóhoz, amikor már csak egy darab inode címzi
meg a file-ot: ennek törlésekor szabadítjuk fel a file által elfoglalt
diszkhelyet. Az ilyen típusú linket hard link-nek nevezzük, és van egy
hátránya: csak ugyanazon a diszken illetve partíción lévõ file-ra
tudunk ilyet létrehozni, mert az inode-on belül nem tudunk mondjuk egy
cserélhatõ floppy vagy CDROM szektorszámaira hivatkozni - egy másik
diszkrõl.
Ezért találták
ki az ún. szimbolikus vagy soft-linket, amely szintén egy link, de úgy
mûködik, hogy a link maga egy speciális file, amiben a hivatkozott file
neve van. Itt általában érdemes relatív nevekkel dolgozni, így késõbb
egész könyvtárszerkezetek, részfák másolásakor, mozgatásakor kevesebb
problémába ütközünk. Mozgatás alatt az is értendõ, ha az adott
filesystem-et a könyvtárstruktúra egy más pontjára illesztjük be!
Láthattuk, hogy a .. itt is a szülõ könyvtárra hivatkozás, a . pedig
logikusan az aktuális könyvtárra utal. Unixban (mint minden), a
könyvtárak is file-ként jelennek meg - ennek az is az elõnye, hogy a
könyvtár neve, a könyvtárban lévõ . file és a könyvtár közvetlen
alkönyvtáraiban lévõ .. hivatkozások mind-mind ugyanarra az inode-ra, a
könyvtár inode-jára mutató hard linkek. Ugye milyen logikus?
Ennyi elméleti alapozás után már éppen itt az ideje, hogy billentyûzetet
ragadjunk, és elkezdjük egy Linux rendszer felfedezését a gyakorlatban is!
Tovább...