E:\Moje dokumenty\HELION\Linux Unleashed\Indeks\57.DOC 841
Rozdzia³ 57. ¨ Jądro systemu 841
Kamran Husain i Tim Parker
W tym rozdziale:
u Uaktualnianie i instalowanie nowych składników jądra systemu
u Kompilowanie kodu źródłowego jądra systemu
u Dodawanie sterowników urządzeń
u Uaktualnianie bibliotek
u Kompilator języka C dla systemu Linux
Poza przypadkami takimi jak instalowanie nowej wersji systemu, instalowanie nowych składników sieci (takich jak NFS czy NIS) czy nowych sterowników urządzeń wymagających specjalnego traktowania nie ma konieczności modyfikowania jądra systemu. Szczegółowe informacje na temat instalowania sterowników urządzeń zwykle są rozprowadzane wraz z oprogramowaniem. Nie jest tak jednak w każdym przypadku, dlatego w tym rozdziale przedstawimy ogólne zasady dotyczące pracy z jądrem systemu.
Na początek powiedzmy wyraźnie, że nie powinieneś modyfikować jądra systemu, jeśli nie wiesz, co chcesz przez to osiągnąć. Jeśli kod źródłowy lub pliki konfiguracyjne zostaną uszkodzone, kernel może być niestabilny, co w najgorszym przypadku może prowadzić do uszkodzenia systemu plików. Uważnie zapoznaj się z przedstawionymi poniżej informacjami i przestrzegaj podanych wskazówek. Modyfikowanie jądra systemu wymaga sporej wiedzy, a w tym rozdziale możemy przedstawić tylko podstawowe informacje.
Obecnie używa się powszechnie kilku różnych wersji Linuxa, nie do końca zgodnych pomiędzy sobą. Z tej przyczyny przedstawione poniżej instrukcje mogą nie działać prawidłowo w Twojej wersji Linuxa. Mimo tego idea pozostaje ta sama, różnice mogą wystąpić tylko w przypadku nazw programów użytkowych i ścieżek dostępu do nich. Do większości wersji Linuxa dołączana jest dokumentacja omawiająca proces kompilowania jądra i zawierająca informacje o położeniu kodu źródłowego i skompilowanych programów.
Zanim podejmiesz jakiekolwiek kroki upewnij się, że posiadasz odpowiedni zestaw dyskietek startowych. Warto również wykonać pełną kopię zapasową systemu plików. Choć proces modyfikowania jądra nie jest trudny, jeśli coś pójdzie nie tak, może okazać się, że nie da się ponownie uruchomić systemu. W takiej sytuacji najprostszym rozwiązaniem jest użycie dyskietek startowych, warto więc posiadać przynajmniej jeden zapasowy ich zestaw.
Ponieważ jądro systemu jest kompilowane za pomocą kompilatora języka C wchodzącego w skład każdej dystrybucji Linuxa, to właśnie na nim skoncentrujemy się w dalszej części tego rozdziału, omawiając jego znaczniki i sposoby stosowania. Nie będzie to oczywiście kompletny opis kompilatora języka C, ale powinien być wystarczający przy podstawowych czynnościach związanych z modyfikowaniem jądra systemu (i kompilowaniem dowolnych programów napisanych w języku C).
Linux jest systemem rozwijającym się bardzo dynamicznie. Nowe wersje jądra systemu bądź też innych komponentów dołączanych do jądra są co jakiś czas udostępniane dla użytkowników. Decyzję o tym, czy należy uaktualnić wersję jądra systemu, musisz podjąć sam – zwykle opiera się ona na danych dotyczących błędów usuniętych w nowej wersji czy też oferowanych przez nią nowych możliwościach. Po dołączeniu nowego oprogramowania prawdopodobnie będzie trzeba odnowić wszystkie dowiązania do jądra systemu, chyba że nowe komponenty są sterownikami urządzeń czy niezależnymi programami użytkowymi.
Mimo wszystko, należy jednak zdecydowanie unikać uaktualniania systemu wraz z każdą nową wersją, i to z kilku powodów. Może na przykład zdarzyć się, że zainstalowane oprogramowanie nie jest zgodne z nową wersją programów użytkowych czy jądra systemu. Może również okazać się, że nowa wersja posiada poważny błąd. Tego typu sytuacje mogą powodować nie kończące się problemy. Większość nowych wersji programów nie zachowuje istniejących informacji konfiguracyjnych, więc konieczna jest także ponowna konfiguracja wszystkich pakietów, które zostały zainstalowane na nowo.
Poza tym, nowe wersje programów pojawiają się na tyle często, iż nie jest wykluczone, że więcej czasu spędziłbyś na ich ładowaniu i instalowaniu niż na faktycznym korzystaniu z systemu. Taka sytuacja może być bardzo męcząca. Liczba zmian wprowadzanych w kolejnych wersjach systemu różniących się tylko numerem pobocznym jest zwykle niewielka, dlatego należy przejrzeć dołączone do niej informacje i upewnić się, że faktycznie warto poświęcić czas na jej instalację.
Z praktycznego punktu widzenia dobrze jest aktualizować system raz lub dwa razy do roku, tylko wtedy, gdy nowa wersja zawiera rozwiązania, które znacznie zmienią sposób, w jaki używasz system. Posiadanie zawsze najnowszej wersji systemu jest kuszące, ale trzeba również brać pod uwagę korzyści wynikające z utrzymywania stabilnego i funkcjonalnego systemu operacyjnego.
Jeśli uaktualniasz wersję oprogramowania, powinieneś zdawać sobie sprawę z faktu, że nie musisz uaktualniać wszystkiego. W kilku ostatnich wersjach Linuxa zmieniało się co najwyżej 5% systemu operacyjnego. Zamiast wymiany całego oprogramowania warto więc rozważyć zainstalowanie tylko tych fragmentów, które faktycznie uległy znaczącym zmianom, czyli zwykle jądra systemu, kompilatora, bibliotek i często wykorzystywanych programów użytkowych. Takie rozwiązanie pozwoli uniknąć konieczności ponownego konfigurowania pozostałych części systemu.
Uaktualnienie, wymiana czy dodanie nowego kodu do jądra systemu jest zwykle procesem dość prostym. Sprowadza się do zdobycia odpowiedniego kodu źródłowego, dostosowania informacji konfiguracyjnych, skompilowania a następnie umieszczenia skompilowanych programów w odpowiednim miejscu tak, by system mógł działać prawidłowo. Proces ten zwykle jest zautomatyzowany za pomocą skryptu powłoki lub programu instalacyjnego – w niektórych przypadkach wszystko sprowadza się do wydania jednego polecenia.
Kod źródłowy nowych wersji jądra systemu dostępny jest zwykle z dystrybucjami rozprowadzanymi na płytach CD-ROM, w węzłach FTP, grupach dyskusyjnych i w wielu innych miejscach. Większość wersji jądra posiada numer składający się z głównego i pobocznego numeru wersji (dwie pierwsze liczby) oraz numeru poprawki (trzecia liczba), na przykład 1.12.123. W większości węzłów FTP czy BBS równocześnie udostępnianych jest kilka wersji jądra – musisz wziąć to pod uwagę, jeśli chcesz załadować jego najnowszą wersję.
Poprawki do kodu źródłowego jądra systemu zwykle nie zawierają całego kodu. Ich instalacja powoduje nadpisanie fragmentów istniejącego kodu źródłowego. Po jego ponownym skompilowaniu poprawka jest już zainstalowana. Tego typu poprawki udostępniane są dość często.
Podczas instalowania poprawki należy ograniczyć do minimum liczbę otwartych plików i działających procesów oraz aplikacji. Pozwoli to uniknąć problemów związanych z pozostawieniem otwartych plików, co może prowadzić nawet do uszkodzenia tablicy I-node. Ponieważ aby zainstalować poprawkę i tak musisz być zalogowany jako root, możesz zakończyć wszystkie niepotrzebne procesy i aplikacje.
W większości przypadków kod źródłowy jest rozprowadzany w postaci skompresowanego (zwykle programem gzip) archiwum programu tar. Taki plik należy rozpakować do katalogu /usr/src, w którym zwykle przechowywany jest kod źródłowy programów. W niektórych wersjach Linuxa do tego celu przeznaczony jest inny katalog – powinieneś więc przejrzeć dokumentację rozprowadzaną z posiadaną przez Ciebie wersją Linuxa lub poszukać w katalogu /usr/src pliku README, w którym powinny znajdować się dokładniejsze informacje.
Często zdarza się, że rozpakowanie pliku do katalogu /usr/src powoduje utworzenie podkatalogu /usr/src/linux, co może prowadzić do nadpisania obecnej w systemie wersji kodu źródłowego jądra. Przed rozpoczęciem rozpakowywania warto więc zmienić nazwę istniejącego katalogu lub skopiować jego zawartość w bezpieczne miejsce, dzięki czemu w przypadku problemów łatwo będzie wrócić do wersji poprzedniej.
Po rozpakowaniu kodu źródłowego należy utworzyć dwa dowiązania symboliczne (o ile nie zostały one utworzone przez program instalacyjny) do katalogu /usr/include. Można to zrobić wydając polecenia:
ln -sf /usr/src/linux/include/linux /usr/include/linuxln -sf /usr/src/linux/include/asm /usr/include/asm
Jeśli w Twoim systemie używane są inne ścieżki dostępu, podstaw zamiast /usr/src/linux odpowiednią wartość. Jeśli takie dowiązania nie istnieją, poprawne uaktualnienie jądra systemu nie będzie możliwe.
Po rozpakowaniu kodu źródłowego i utworzeniu odpowiednich dowiązań można rozpocząć proces kompilacji. W tym celu niezbędny będzie kompilator gcc lub g++ (kompilator GNU języka C i C++) lub inny zgodny z nimi kompilator. Należy sprawdzić w dokumentacji dołączonej do nowej wersji kodu źródłowego czy używana wersja kompilatora jest odpowiednia, ponieważ zdarza się, że nowe wersje jądra nie dają się skompilować za pomocą starszych wersji kompilatorów.
Następnie należy przejrzeć plik /usr/src/linux/Makefile (w niektórych dystrybucjach może on znajdować się w innym katalogu). Znajdź w nim wiersz definiujący zmienną ROOT_DEV, określającą urządzenie, na którym zapisany jest główny system plików. Zwykle definicja ta ma postać
ROOT_DEV = CURRENT
Jeśli wartość zmiennej ROOT_DEV jest inna, upewnij się, że jest ona odpowiednia dla Twojego systemu. Jeżeli w pliku Makefile nie ma takiej definicji, należy ją dodać.
Proces kompilacji rozpoczyna się po przejściu do katalogu /usr/src/linux i wydaniu polecenia
make config
uruchamiającego program make, generujący odpowiednie polecenia kompilujące pliki źródłowe. W niektórych wersjach Linuxa proces ten może wyglądać nieco inaczej – odpowiednich informacji należy szukać w dokumentacji dołączonej do plików źródłowych.
W następnym kroku program config zadaje serię pytań dotyczących różnych aspektów konfiguracji jądra, na które należy odpowiedzieć przed rozpoczęciem właściwej kompilacji. Pytania te dotyczą między innymi typu dysku twardego, procesora, typów używanych partycji czy innych urządzeń dołączonych do komputera, na przykład napędów CD-ROM. Powinieneś odpowiedzieć na nie najlepiej, jak potrafisz. Jeśli masz wątpliwości co do którejś z odpowiedzi, wybierz odpowiedź domyślną albo tę, która wydaje się być najodpowiedniejsza. W najgorszym przypadku – jeśli system nie będzie działał prawidłowo – będzie trzeba powtórzyć cały proces od początku (oczywiście pod warunkiem, że przygotowałeś dyskietki startowe).
Następnie należy ustalić wszystkie zależności pomiędzy plikami kodu źródłowego. Ten etap często jest pomijany, ale takie postępowanie może powodować mnóstwo problemów. Aby ustalić zależności dla zainstalowanej wersji kodu źródłowego jądra systemu, wydaj polecenie:
make dep
Jeśli w skład instalowanego oprogramowania nie wchodzi plik zależności (o nazwie dep), powinieneś upewnić się, że odpowiednie czynności podejmowane są w czasie wykonywania innych etapów konfiguracji oprogramowania (informacje takie znajdują się w dokumentacji dołączonej do plików źródłowych).
Na koniec pora rozpocząć kompilację nowego jądra – w tym celu należy wydać polecenie
make Image
które spowoduje skompilowanie jądra i pozostawienie go w katalogu bieżącym (zwykle /usr/src/linux). Jeśli chcesz utworzyć skompresowaną wersję jądra systemu, wydaj polecenie
make zImage
Nie wszystkie dystrybucje Linuxa pozwalają na kompresowanie jądra systemu w trakcie jego kompilacji.
Ostatnim krokiem jest skopiowanie nowej wersji jądra systemu na dysk, z którego uruchamiany jest system, lub też na dyskietkę startową. Polecenie
cp Image /dev/fd0
spowoduje umieszczenie kopii jądra systemu na dyskietce. Jeśli chcesz umieścić ją gdzieś indziej, podstaw odpowiednią nazwę urządzenia. Jeżeli natomiast do uruchamiania systemu używany jest program LILO, wówczas aby zainstalować nowe jądro, należy uruchomić program instalacyjny lub program /usr/lilo/lilo – dokładniejsze informacje na ten temat przedstawiliśmy w rozdziale 4. „Program LILO”.
Teraz pozostaje tylko uruchomić ponownie system i sprawdzić, czy nowe jądro prawidłowo ładuje się do pamięci. Jeśli wystąpią jakieś problemy, należy uruchomić system z dyskietki startowej i powtórzyć cały proces. W dołączonej do kodu źródłowego dokumentacji znajdziesz wskazówki dotyczące rozwiązywania niektórych problemów oraz informacje o ewentualnych zmianach w procesie kompilacji jądra.
Nowe sterowniki urządzeń można również dołączać do istniejącej wersji jądra bez konieczności jego konfiguracji i kompilowania. Z taką sytuacją można często zetknąć się w przypadkach, gdy do systemu dodane zostanie takie urządzenie, jak karta multiport czy dysk optyczny, do których obsługi niezbędne jest załadowanie odpowiednich sterowników podczas uruchamiania systemu. Może również zdarzyć się, że będziesz chciał zainstalować jakiś rodzaj oprogramowania podnoszącego poziom bezpieczeństwa systemu i wymagającego modyfikacji samego jądra systemu.
Sterowniki wymagające kompilacji jądra przeważnie rozprowadzane są wraz z odpowiednią dokumentacją. Zwykle otrzymany kod źródłowy należy umieścić w tym samym katalogu, w którym znajduje się kod źródłowy jądra systemu (na przykład /usr/src). Aby dodać do jądra systemu nowy fragment kodu, trzeba zmodyfikować plik Makefile – ręcznie bądź też za pomocą odpowiedniego skryptu instalacyjnego. W niektórych przypadkach do kodu źródłowego sterowników dodawany jest osobny plik Makefile.
Następnym krokiem jest skompilowanie jądra wraz z nowymi sterownikami. Proces ten nie różni się od opisanego w poprzednim podrozdziale – skompilowane jądro należy skopiować na dyskietkę startową lub zainstalować za pomocą programu LILO. Zwykle cały proces nie zabiera więcej niż dziesięć minut i raczej nie sprawia kłopotów, chyba że dostawca oprogramowania kiepsko wywiązał się ze swych obowiązków. Przed instalacją upewnij się, że nowe sterowniki będą działać z Twoją wersją jądra systemu – odpowiednie informacje znajdziesz w plikach tekstowych dołączonych do kodu źródłowego oraz w plikach dotyczących zgodności z różnego typu oprogramowaniem, rozprowadzanych z większością wersji Linuxa.
Większość programów przeznaczonych dla systemów linuxowych korzysta z bibliotek współużytkowanych (ang. shared libraries; jest to zestaw podprogramów, które mogą być wykorzystywane przez różne aplikacje). Jeśli po uaktualnieniu jądra systemu przy uruchomianiu programów wyświetlany jest komunikat
Incompatible library version
oznacza to, że biblioteki również wymagają uaktualnienia. Większość bibliotek jest kompatybilna wstecz, co oznacza, że programy wykorzystujące starsze wersje bibliotek będą działać poprawnie również po zainstalowaniu nowych wersji bibliotek.
Nowe wersje bibliotek pojawiają się rzadziej niż nowe wersje jądra systemu i są rozprowadzane w ten sam sposób. Zwykle do nowych wersji jądra dołączane są pliki tekstowe zawierające informacje o wymaganych bibliotekach i wskazujące miejsca, w których można zaopatrzyć się w ich najnowsze wersje.
Nowe wersje bibliotek rozprowadzane są najczęściej w postaci skompresowanego archiwum programu tar, więc proces ich rozpakowywania jest taki sam, jak plików zawierających kod źródłowy jądra systemu, z tym że katalogami docelowymi są zwykle katalogi /lib, /usr/lib i /usr/include. Pliki z rozszerzeniami .a i .aa trafiają przeważnie do katalogu /usr/lib, natomiast pliki obrazów bibliotek współużytkowanych, których nazwy mają postać libc.so.wersja, do katalogu /lib.
Po zainstalowaniu nowych wersji bibliotek czasem zachodzi konieczność ręcznej modyfikacji dowiązań symbolicznych, tak by prowadziły do najnowszych wersji bibliotek. Przykładowo, jeśli używasz biblioteki libc.so w wersji 4.4.1 i uaktualniłeś jej wersję do 4.4.2, powinieneś zmodyfikować odpowiednie dowiązanie, wydając polecenie:
ln –sf /lib/libc.so.4.4.1 /lib/libc.so.4
Ostatni argument jest nazwą uaktualnianej biblioteki – nazwy te mogą być różne w zależności od dystrybucji – należy to sprawdzić w dokumentacji.
W taki sam sposób należy zmodyfikować również dowiązanie dla biblioteki libm.so. Dowiązań symbolicznych nie należy usuwać, ponieważ programy korzystające z bibliotek współużytkowanych (m.in. program ls) nie będą działać poprawnie.
Wolf-1