Kilka lub nascie linuksów na jednej partycji
Linuks jest jak.... Po prostu jest. Niech ta sentencja zostanie potraktowana jako wstęp.
A więc tak (nie zacząłem od 'więc' :> ), chcemy mieć kilka tych uniksopodobnych systemow i jedną partycję, na której one siedzą i się zmieniają w zależności od wyboru w lilo/grubie. Niestety rozczaruję was, albo też uszczęśliwie: jeśli ktoś myśli o tym, aby mieć tylko swapa i tylko jedną partycję systemową, to owszem jest to mozliwe. Po grzebaniu w źródłach i ręcznej kompilacji (np. hexedytorem - cii nikt sie nie polapie, wazne, zeby zmienić ścieżkę do ld-linux.so.2, bo jest wkompilowana na sztywno, a przecież bedziemy robić mv /lib /oldsysdestination, a potem mv /newsyssource/lib / i nie mozemy sobie w międzyczasie podciąc galęzi na ktorej siedzimy - dośc dygresii, to inna bajka, może opowiem ja kiedyś) , skopiowaniu kilku/nastu bibliotek i plikow wykonywalnych, napisaniu skryptów i oczywiscie ostrego grzebania w skryptach uruchomieniowych (a wlaściwie w jednym dotyczącym runlevelu szóstego, za to w każdym instalowanym systemie, mizło byc dość bajek :>, zresztą mam częśc zrobioną, może ją sbie ktoś obejrzy i połapie się o co biega ftp://carramba.no-ip.org:2121/linux/ - katalog CHS, który musi byc w katalogu /, żeby zdziałało, jeśli go jeszcze nie ma, to trzeba poczekać)
Ostrzeżenie 1. Będziemy instalować lilo w dwóch miejscach, w MBR oraz w bootsektorze partycji linuksowej, jest to esencja całej zabawy, więc jesli ktoś ma w MBR bootloader innego systemu i nie może go przenieść gdzie indziej, bądź nie może z niego zrezygnować na rzecz lilo, to z góry uprzedzam, że nie jest to artykuł dla niego.
Ostrzeżenie 2. Pracujemy tylko jako root. Praktycznie operujemy tylko na plikach których wlaścicielem jest root lub wykonujemy polecenia dostepne tylko dla root'a.
Przepis:
. Składniki
Linuksów kilka, wedle wyboru, do smaku i koloru dowolność. Partycji trzy, pierwsza duża, rozmiarow dowolnych, aczkolwiek jak wór, im wieksza, tym wiecej kotów tam zmiescimy. Wtóra mała, pamieci rozmiaru koło dwu- lub trzykrotnego, do smaku. Trzecia maciupka, rozmiaru ośmiu dziesiątek milionów bajtów (uprasza się o przeczytanie komentarza w punkcie 'Oj maluśki, maluśki').
: Przygotowanie ogolne
Partycje formatujemy, systemy plików dowolne, pod warunkiem że druga partycja będzie robiła za swap (co wynikalo z opisu rozmiaru), a trzecia nie będzie formatowana dla systemu plików, ktorego dziennik (jurnal) zajmie znaczącą cześc dysku (np. reiserfs - około 30 MB - prawie 40%, chore). Proponuje ext2 lub ext3. Od tej pory największą partycję bedę nazywał hda1, swap jako hda2 i najmniejszą jako hda3.
Wybieramy pierwszy system. System ten będzie systemem najmniejszym (ma sie zmieścić na t), ale jednocześnie najważniejszym, nadzorczym na resztą. Jakiś lightwigthowy, ktory mozna postawic w minimalnej objętości i instalujemy na hda1 (wbrew pozorom na największej, nie na najmniejszej, potem sie go skopiuje, okroi jeszcze bardziej i skonfiguruje). Jaki ma to być system ? Ano przede wszystkim taki, ktory lubimy, który bedzie mógł zamontowac obie partycje (reszta systemów nie musi mieć możliwości montowania najmniejszej partycji), który znamy dobrze, jest łatwo dla nas konfigurowalny itd. Systemy, które moga malo zająć. Może to być na przykład sourcemage, lunar, slackware (ekhm, ekhm :) ), debian, gentoo, tsl, .... Lunar, gentoo i sourcemage mają mozliwość skompilowania jądra (i odchudzenia go) już podczas instalacji systemu, ale za to nie mają części oprogramowania uzytkowego (np. bardzo wygodnego mc), a przecież mimo, że bedzie to system malutki, może być jednocześnie pełnowartosciowym uzytkowym systemem, co prawda na pewno bez ixów, ale bash + mc dają spore mozliwości. Tsl jest systemem przeznaczonym na serwery, bardzo podobnym do slacka, ale nie ma mc (przyczepilem się do midnight commandera, ale art prawdopodobnie trafi w ręce niejednego początkującego). Jeszcze jedna rzecz przemawia na korzyść slacka i tsl-a. Brak systemu repozytorium (emerge, apt-get, urpmi czy jak to tam w róźnych systemach bywa), a walczymy przecież o kazdy bajt (mamy 80 MB tylko). Slabo znam debiana, więc o nim sie nie wypowiem, byc może powali wszytkie te dystrybucje na kolana, być może nie. Znalazł się na tej liście, bo spełnia zasadniczo wymogi (po instalacji jest maly :) ). Nie warto rownież instalować programów, których nie wykorzystamy (syslog, cron, uslugi sieciowe, x/inetd i tym podobne), bo po wałka w systemie, który działać ma przez 10 sekund ?
Ważna rzecz. Nie opiszę tu w żaden sposób przygotowania grub'a, więc na system podstawowy najlepiej wybrać cos co ma lilo, albo jeśli nie ma lilo (przypadłość wszystkich RedHatoPochodnych), to ładnie skopiować z innego systemu, np. od znajomego, lub ściągnąc i po prostu zainstalować/skompilować (przynajmiej 2 pliki : /sbin/lilo i /lib/libdevmapper.so.1.00). Do pierwszego staru lilo nie bedzie porzebne, dopiero przy konfiguracji dodatkowych systemów. Więc zawsze zdązycie w to zaopatrzyć. Co jeszcze przemawia za lilo ? Otóż zawsze udało mi sie je skonfigurować, zawsze robiło to co chciałem, natomiast z grub'em miałem nie raz kłopoty. Tak, jestem uprzedzony :>
:. Oj maluśki, maluśki
Hmm założenie, że system i partycja dla niego ma byc mala... Nie musi być spełnione. To jest moje prywatne założenie, ponieważ wyciąłem sobie ta partycję ze swapa. Nie moglem dzielić dużej partycji, bo juz mialem na niej system, którego nie daloby się odtworzyć w obecnym stanie (mandrejk, nad którym siedziałem prawie 3 miesiące i który po tym czasie jedynie kolorami wypisującymi podczas startu 'Denaturatix 0,75l linux release' mandrejka przypomina).
Natomiast, jesli ktoś nie jest przywiązany do status quo, nie musi absolutnie trzymać się kurczowo i drżeć na mysl o chirurgicznej ingerencji w system (a jak skasuje za dużo i mi nie wstanie ? Zresztą to nie ból, opiszę jak robić, żeby zrobić). Dla takich wlasnie linuksożerców rozmiar partycji hda3 jak i dystrybucja mogą być dowolne, pozostawiam to kwestii fantazji. Jednak trzeba się liczyć z jedna rzeczą. Ten system będzie miał wolniejszy od innych start i zejście, bo bedzie musiał za każdym razem wykonać 2 dodatkowe czynności (jedną przy starcie i jedna przy shutdownie). Ale o tym dalej.
:: Przygotowanie systemu podstawowego (wersja maksymalistyczno wygodnicka).
Krótko. Po prostu instalujemy system bezpośrednio na hda3 :) Bootloader do pierwszego startu dowolny, gdziekolwiek, jak system wstanie właduje mu się lilo. Potem trzeba je skonfigurować dla MBR i zainstalować. Jedna rzecz, którą trzeba wykonac po instalacji i przebootowaniu trzeba zainstalować też lilo w bootsektorze partycji hda1, Wykonać trzeba '/sbin/lilo -b /dev/hda1'. W razie niepowodzeń (nie powinno być żadnych) odsyłam niestety do man lilo i man lilo.conf oraz do /usr/share/doc/lilo
Następny punkt dla idących ta drogą to 'Lilo cd.'
::. Przygotowanie systemu podstawowego (wersja minimalistyczna).
This is the hardest part of the work, so please, be careful
Zainstalowaliśmy system (szlaczek, prawda ? :> ). System wstał, żyje, my jesteśmy zalogowani jako root. Bierzemy sie za kasowanie? Być może... Robimy następującą rzecz:
wklepujemy z konsoli
mkdir /SYSTEMY
mkdir /SYSTEMY/nasz_system
- nasz_system - pofantazjujcie sobie i wymyślcie inną bardziej adekwatną nazwę
- znaczkiem # oznaczał będę komentarze pomiedzy liniami kodu/rozkazów/wydruków
mkdir
telinit 1
albo: init 1
mount
Tu słow kilka komentarza. Po pierwsze dlaczego telinit 1 ? Spróbujcie skopiować /proc w innym trybie. Po drugie, po wykonaniu mount wypiszą się wszystkie zamontowane systemy. Przykładowo moze sie pokazać coś takiego:
/dev/hda1 on / type reiserfs (rw,noatime,notail)
/dev/hda3 /mnt/hda3 type ext3 (rw)
none on /proc type proc (rw)
none on /proc/bus/usb type usbfs (rw)
none on /sys type sysfs (rw)
none on /tmp type tmpfs (rw)
Odmontowujemy wszystko poza katalogiem głownym. Najlepiej od konca. Czemu ? Prosze spojrzec na linijki zawierajace /proc i /proc/bus/usb, nie odmontuje się /proc, dopóki zamontowane bedzie /proc/bus/usb.
umount /tmp
umount /sys
umount /proc/bus/usb
umount /proc
umount /mnt/hda3
lub umount /dev/hda3 obojetnie czy partycje odmontowujemy poprzez punkt montowania, czy poprzez nazwę urzadzenia
Mozna spróbować wpisać 'umount -a'
Dalej odpalamy midnigth commandera, a co idziemy na łatwiznę (kto nie ma używa cp z zachowaniem atrybutów)
mc
Jak w norton/total commanderze zaznaczamy insertem wszystko, poza katalogiem /SYSTEMY. Wchodzimy do /SYSTEMY/nasz_system w drugim panelu. Wciskamy F5 (kopiuj/copy), nie zmieniamy żadnej z zaznaczonych opcji.
Mamy kopię. Montujemy z powrotem wszytkie systemy plików poleceniem 'mount -a' i ewentualnie wracamy do trybu 3 (domyślnego dla naszego systemu) poleceniem 'telinit 3' lub 'init 3'.
Jesli kopia zajmuje więcej niż 80 MB zaczynamy się bawić poleceniem rm i robimy to dopóki system nie zmieści się na /dev/hda3. Co mozna skasować na pewno ? Ano wszystkie pliki z ustawieniami jezyka, mapowania klawiatury, stref czasowych, Wszystko co się znajduje w katalogach X11 (łącznie z katalogami). Swobodnie również można wywalić wszystkie źródła, katalogi include, src i wszelkie elementy developerskie. W katalogach /lib /usr/lib kasujemy jedynie to, co na pewno niebędzie nam potrzebne pliki typu libjpeg (avi,png,gif alsa, arts i takie tam) w /lib/modules kasujemy moduły jądra tylko te, o których wiemy, że na pewno sie nie przydadzą (jesli mamy nvidię, to na pewno radeon-costamdalej, s3-jakaskoncowka czy trident-bleble nam sie nie przyda z zalożenia :> ). Kasujemy z umiarem, nic na siłe, jesli czegos nie jesteśmy pewni zostawiamy. Chcemy przecież, żeby ten system wstał. Co pewnien czas kopijemy okrawaną kopię na partycję /hda3 (jak wyżej pokazane zamontowana może być w /mnt/hda3). Mc ma fajną opcje, może pokazywać rozmiar katalogu w dolnej części panelu (F9/polecenie/wyświetl rozmiary katalogów), można przynajmniej porównawczo dowiedzieć się, czy system moze się zmieścić, ale jest jeden ból zawiesza sie na symlinkach rekurencyjnych (powiedzmy w katalogu /katalog jest symlink do /katalog - tak często bywa w np. w /boot lub jakoś w /boot/grub, dlatego dobrze jest to robić w runlevelu 3, żeby moc zmienić konsole i wpisać 'pkill mc'). Polecenie df pokazuje ilość wolnego miejsca na dyskach. Jeśli system się nie mieści kasujemy wszystko z katalogu /mnt/hda3 i wracamy do odchudzania systemu. Aż do skutku.
Oka, dotarliśmy do momentu, gdy mc nie wyrzucił nam braku miejsca przy kopiowaniu. Przygotujemy sobie lilo (prawda, że sciagneliście już i macie je ? :>)
W systemie zazwyczaj poza ekstraordynarnym vi (emacs'a nie istalowaliśmy z załozenia) powinien być edytor o nazwie pico, albo nano. Odpalamy któraś z poniższych komend:
mcedit /mnt/hda3/etc/lilo.conf
nano -w /mnt/hda3/etc/lilo.conf
pico -w /mnt/hda3/etc/lilo.conf
vi /mnt/hda3/etc/lilo.conf (wyjście - wcisnąć ":" i "q" tyle wiem)
powiedzmy, że mamy tam miedzy innymi taki wpis:
image = /boot/vmlinuz
root = /dev/hda1
label = Linux
append = "jakies opcje"
initrd = /boot/initrd
vga = 791
read-only
optional
jakieś inne mozliwe wpisy które nie muszą wystapić, właściwie z tych powyżej muszą wystąpic tylko label, root i image,
reszta zależna jest od konfiguracji jądra i systemu
Kopiujemy całość (F3 zaznaczanie w mcedit i F5 kopiowanie) i w kopii zmieniamy label na nazwę, która się nie powtórzy (dla przykładu: maly_system), root na /dev/hda3, image na /mnt/hda3/boot/vmlinuz i jesli wystepuje initrd na /mnt/hda3/boot/initrd (vmlinuz i initrd mogą miec jakies dodatkowe dopiski, mniejsza o większość). Sprawdzamy zmienną boot, jeśli ma wpisane /dev/hda zostawiamy, jeśli jest /dev/hda1 niestety, trzeba to zmienić i skasować jedynkę. Zapisujemy, wychodzimy i wklepujemy /sbin/lilo. Jesli wystąpiły blędy poprawiamy lilo.conf (prawdopodobnie za długa nazwa, w nazwie spacje bądź źle wpisane /mnt/hda3).
Edycja fstab.
mcedit /mnt/hda3/etc/fstab (lub pico/nano/vi)
Trzeba zmienić urządzenie montowane jako / na z /dev/hda1 na /dev/hda3 oraz zmienić system plików jesli hda1 i hda3 mają różne. natomiast /dev/hda1 trzeba podmontować np. w /mnt/big. Można wywalić/zakomentować swapa (minimalnie szybszy start, poza tym, ten system ma byc przeznaczony do wykonania jednego skryptu i zrebootowania. ewentualnie podczas pracy zawsze mozna wpisać 'swapon /dev/hda2') Dla przykładu mój fstab:
before:
/dev/hda2 swap swap defaults 0 0
/dev/hda1 / reiserfs defaults 1 1
/dev/hda3 /mnt/hda3 ext3 defaults 1 2
/dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0
devpts /dev/pts devpts gid=5,mode=620 0 0
proc /proc proc defaults 0 0
after:
/dev/hda1 /mnt/big reiserfs defaults 1 2
/dev/hda3 / ext3 defaults 1 1
devpts /dev/pts devpts gid=5,mode=620 0 0
proc /proc proc defaults 0 0
# tego nie potrzebujemy (co nie znaczy, że nie może być)
#/dev/hda2 swap swap defaults 0 0
#/dev/cdrom /mnt/cdrom iso9660 noauto,owner,ro 0 0
Jesli nie istnieje katalog /mnt/hda3/mnt/big to go tworzymy za pomocą 'mkdir /mnt/hda3/mnt/big'
Po pomyślnym zainstalowaniu lilo i edycji fstab'a wpisujemy reboot albo shutdown -r now, składamy rączki i się modlimy, do momentu, gdy pokaże sie menu lilo. Wtedy szybko przestajemy sie modlić, wybieramy maly_system, wciskamy enter i wracamy do modlitwy.
Jeśli system wstal, jesteśmy zadowoleni, możemy sie zalogować na roota (to samo haslo, bo to kopia systemu), dziala nam to co chcemy, mimo ewentualnych jakichś błedów podczas bootowania.
Co zrobić, gdy system nie wstanie ? To zależy co padło. Możliwosci są trzy - za duzo wycięte, źle skonfigurowany fstab lub lilo. Odpowiednio sie cofamy (wciskamy ctrl-alt-del i czekamy na reebot lub jeśli nie dało rady robimy to z palca resetem :/ odpalamy domyslną pozycje z lilo). Przykra sprawa, jesli za duzo wycięte, to zaczynamy od początku tego punktu (telinit 1, umount -a, cp, telinit 3, rm, cp, pico, lilo). Jeśli lilo, lub fstab, to tylko modyfikujemy co potrzeba.
::: Konfiguracja systemu
Pomyslmy co mamy zrobione. Mamy 2 systemy. Jesteśmy w malym (okrojonym). Mamy jedno lilo zainstalowane prawdopodobnie w mbr. Ale to lilo pochodzi z systemu dużego, a nie malego okrojonego. Bedziemy edytować 2 pliki /etc/lilo.conf (dla dużego systemu) i /etc/lilo.conf (dla małego systemu). Tak to ten sam plik, żadna pomyłka. I jest to dośc ważny kawałek pracy, więc proszę się skupić. Poprzednia edycja słuzyła tylko do odpalenia małego systemu. W tej chwili /etc/lilo.conf jest oryginalną pierwotną kopią pierwotnego systemu, skopiowaliśmy ten plik zanim zaczelismy modyfikować tamten. Tak więc w /etc/lilo.conf zmieniamy wpis z boot = /dev/hda na boot = /dev/hda1 (teraz dostawiamy jedynkę) wykonujemy po kolei polecenia:
cp -f /etc/lilo.conf /mnt/big/etc/lilo.conf
chroot /mnt/big /sbin/lilo
Mamy w bootsektorze hda1 lilo oryginalnego systemu :)
:::. Lilo cd. (tu wchodzą z powrotem wygodnickie leniwce, ominęło ich najlepsze)
Edytujemy ponownie /etc/lilo i zmieniamy wpisy na : boot = /dev/hda, root = /dev/hda3, zmieniamy dopowiednio default = Linux i label = Rescue. Od tej pory nasz minimalistyczny system nie bedzie domyślnym wyborem (wczesniej też nie był), bedzie natomiast krył się pod nazwą Rescue. Dopisujemy również coś takiego:
other = /dev/hda1
label = Linux
odpalamy '/sbin/lilo' i instalujemy lilo
Na wszelki wypadek wykonujemy jeszcze '/sbin/lilo -b /dev/hda3'. Jesli jakimś cudem nadpiszemy MBR, to zawsze w bootsektorze naszej partycji bedzie program umożliwiający start systemu.
Co nam to daje ? Ano załadowania bootloadera z bootsektora hda1 (czyli lilo ktore instalowaliśmy chwilke wczesniej). Mniejsza czy zachowamy sobie nieokrojony system, czy go wyrzucimy, ale wpis w bootsektorze byl nam potrzebny, żeby moć stworzyc domyslny wybór. Własnie...
Mozemy sie zastanowic, czy oryginalny (nieokrojony) system nie przydalby nam się. Jesli tak, to tworzymy sobie katalog /mnt/big/SYSTEMY/nasz_nieokrojony_system i przenosimy tam wszytko poza samym katalogiem SYSTEMY. Dejavu ? Juz to kiedys robiliśmy, chociaż sćiezka wtedy byla troche krótsza... A no tak, przy tworzeniu wersji minimalistycznej. A ona tam wciąż jest :) To czy ją skasujecie, wasza sprawa. Pracujecie na kopii minimalistycznej kopii maksymalistycznego systemu, jak dla mnie troche za długo sie to wszystko wymawia, a nieuzywana kopia na hda1 jest niepotrzebna. Więc skrócilibyśmy nazwę naszego systemu na minimalistyczą kopię wpisując jednocześnie 'rm -rf /mnt/big/SYSTEMY/nasz_system' podśpiewując sobie pod nosem ulubioną melodię. Mnie osobiście, gdy kasuję system za pomocą rm -rf przechodzi mily dreszczyk :d. Ale tego nie zrobimy. Póki co to tylko jakieś 80 MB, o ile nie zdecydawaliscie sie sami na więcej. Ta kopia będzie nam potrzebna do testów. Dla tego systemu też zrobimy małe grzebanie w lilo trzeba zmienić parametr boot na /dev/hda1.
Ok. Podsumowanie, żebyśmy się nie pogubili. Na hda3 jest mały system, sprawny, dzialający. Mamy zainstalowane lilo w MBR i w bootsektorze /dev/hda1. Mamy też oryginalny system w katalogu SYSTEMY/nasz_nieokrojony_system i okrojoną kopię w katalogu SYSTEMY/nasz_system na partycji hda1. Świetnie koniec monotonii, kopiowania, edytowania :) Czas na basha i skrypty... Czy ja zdanie przedtem pisalem koniec edytowania ? Kłamalem. Koniec tylko nudnego kopiowania. Czas troche pogłówkować
:::: Skrypty uruchomieniowe
Na początku wpomniałem, że nasz system bedzie wykonywał 2 dodatkowe czynności.
Sprawdzenie systemu plików przy starcie, bo wbrew pozorom, mimo, że może byc to najmniejszy system jest systemem najważniejszym. Jeśli system nasz stoi na ext2 lub ext3 wpisujemy sobie 'tune2fs -c 1 /dev/hda3' Co to daje ? Ano sprawdzanie systemu plików przy każdym uruchomieniu.
Aktualizacja lilo przy wyłączaniu systemu. Chcecie, czy nie, ale ten system musi móc wstać. Bedziecie instalowali różne inne, możecie nadpisać nawet przy zmianie systemu.
A więc dytujemy skrypt systemowy. W zalezności od systemu różnie to będzie. Trzeba poszukać w /etc/inittab wpisu 'l6:6:' i 'l0:0:'
Slackware
wpis w inittab : l0:0:wait:/etc/rc.d/rc.0
plik : /etc/rc.d/rc.6 <- rc.0 jest symlinkiem do rc.6
dopisanie poniżej deklaracji PATH '/sbin/lilo'
Aurox (prawdopodobnie rownież inne RedHaty) i Mandrake
wpis w inittab : l6:6:wait:/etc/rc.d/rc i l0:0:wait:/etc/rc.d/rc
plik: /etc/rc.d/rc
dopisanie lilo - ponizej naglówka wpisujemy coś takiego :
( [ "$1" = "6" ] || [ "$1" = "0" ] ) && /sbin/lilo
lub bardziej zrozumiale (nie sprawdzałem, czy podziała):
if ( [ "$1" = "6" ] || [ "$1" = "6" ] ) ; then
/sbin/lilo
fi
SuSE : podonie jak w Auroksie, jedyna rożnica, jest taka, /etc/rc.d jest symlinkiem do /etc/init.d i w inittab jest zamiast lX:X:wait:/etc/rc.d/rc lX:X:wait:/etc/init.d/rc.
Trzecia rzecz, to dopisanie wywołania naszego skryptu zmieniającego systemy (/etc/rc.d/rc.setsys) do /etc/rc.d/rc.local i zrobienie do niego symlinka 'ln -sf /etc/rc.d/rc.setsys /usr/sbin/setsys'
Punkt kontrolny dla złapania oddechu:
System wstaje, sprawdza system plików, instaluje/naprawia lilo przy wyjściu, a najwazniejsze, czyli wachlowanie systemami przed nami ...
::::. Podmiana systemow
Na początek skrypt, później go omówimy
#! /bin/sh
#
# Version: @(#)/etc/rc.d/rc.setsys 0.10 03/20/2005
#
# Author: Paweł Szcześniak, <flabra@satanbsd.org>
#
# Tell the viewers what's going to happen...
PATH=/sbin:/etc:/bin:/usr/bin
mountpoint="/mnt/big"
subdir="/SYSTEMY"
abort() {
echo "There is no game with operating system !!"
echo "ABORTING !"
exit 1
}
filesnotfound() { ## missingfileordirectory
echo "ERROR : Not all files or direcories found !!!!"
echo "Missing : $1 !!!"
abort
}
filesfound() { ## foundfileordirectory
echo "ERROR : Found files or direcories !!!!"
echo "Found : $1 !!!"
abort
}
errormoving() { ## foundfileordirectory
echo "ERROR : during moving file/direcotiry !!!!"
echo "File : $1 !!!"
abort
}
notspecified() {
echo "ERROR : new system not specified"
echo
echo "usage :"
echo " $0 system-name"
echo " or"
echo " $0 --bootloader-update"
echo " or"
echo " $0 none - to move current system into it's home directory"
echo
echo "You can also specify a kernel commandline newsys=systemname"
echo " (eg. in lilo.conf append="newsys=suse-9.2")"
echo
abort
}
ok() {
echo "ok :-)"
}
empty() {
echo "empty :-)"
}
checksystem() { ## systemname currentsystemsubdir
[ -f $mountpoint$subdir/$1/system.list ] || filesnotfound $mountpoint$subdir/$1/system.list
echo -n "> $1 : "
j=`wc -l < $mountpoint$subdir/$1/system.list`
i=1;
while [ $i -le $j ] ; do
f=`head -n $i $mountpoint$subdir/$1/system.list | tail -n 1`
( [ -f $mountpoint$2/$f ] || [ -d $mountpoint$2/$f ] ) || filesnotfound $mountpoint$2/$f
i=$[i+1]
done
ok
}
checkothers() { ## currentsystem
k=1
echo "Checking other systems ..."
while [ $k -le $sl ] ; do
sys=`head -n $k $mountpoint$subdir/systems.list | tail -n 1`
( ! [ "$sys" = "$1" ] ) && checksystem "$sys" "$subdir/$sys"
k=$[k+1]
done
}
setcurrsystem() {
echo -n "$1" > $mountpoint$subdir/current_system
curr="$1"
}
checkdir() { ## systemname subdir
echo -n "> checking $mountpoint$2/ : "
l=`wc -l < $mountpoint$subdir/$1/system.list`
m=1;
while [ $m -le $l ] ; do
f=`head -n $m $mountpoint$subdir/$1/system.list | tail -n 1`
( [ -f $mountpoint$2/$f ] || [ -d $mountpoint$2/$f ] ) && filesfound $mountpoint$2/$f
m=$[m+1]
done
empty
}
movesystem() { ## systemname oldsubdir newsubdir
echo -n "> moving $1 form $mountpoint$2/ to $mountpoint$3/: "
o=`wc -l < $mountpoint$subdir/$1/system.list`
n=1;
while [ $n -le $o ] ; do
f=`head -n $n $mountpoint$subdir/$1/system.list | tail -n 1`
mv -f $mountpoint$2/$f $mountpoint$3/$f || errormoving $mountpoint$2/$f
n=$[n+1]
done
ok
}
switchsystems() { ## oldsystemname newsystemname
if [ ! "$1" = "" ] ; then
checkdir "$1" "$subdir/$1"
movesystem "$1" "" "$subdir/$1"
setcurrsystem
cd $mountpoint
$mountpoint$subdir/$1/postmove "$1" "$mountpoint" "$mountpoint$subdir" "uninstalling"
fi
if [ ! "$2" = "none" ] ; then
checkdir "$2"
movesystem "$2" "$subdir/$2"
setcurrsystem "$2"
cd "$mountpoint$subdir/$2"
$mountpoint$subdir/$2/postmove "$2" "$mountpoint$subdir" "$mountpoint" "installing"
fi
}
updatebootloader() { ## systemname
echo "Updating bootloader ..."
$mountpoint$subdir/$1/bootloader
}
checknew() { ## systemname
k=1
echo -n "Seeking for $1 ... "
while [ $k -le $sl ] ; do
sys=`head -n $k $mountpoint$subdir/systems.list | tail -n 1`
if [ "$sys" = "$1" ] ; then
echo "found :-)"
return 0
fi
k=$[k+1]
done
echo "not found !!!"
exit 1
}
################
### START
################
dir=`pwd`
[ -f $mountpoint$subdir/current_system ] || touch $mountpoint$subdir/current_system
curr=`head -n 1 $mountpoint$subdir/current_system`
new=$1
[ "$new" = "" ] && new=`cat /proc/cmdline | awk -F 'newsys=' '{ print $2 }' | awk -F ' ' '{ print $1 }'`
[ "$new" = "" ] && notspecified
if [ "$new" = "--bootloader-update" ] ; then
[ "$curr" = "" ] && echo "There is no current system" || updatebootloader "$curr"
exit 0
fi
sl=`wc -l < $mountpoint$subdir/systems.list`
[ "$new" = "none" ] || checknew "$new"
echo "Starting system manager ..."
echo "Checking systems files ..."
if [ "$curr" = "" ] ; then
echo "There is no current system"
else
echo "Checking current system ..."
checksystem "$curr"
fi
[ $sl -gt 1 ] && checkothers "$curr"
[ "$curr" = "" ] && echo "Setting new system to $new" || echo "Switching system $curr to $new ..."
( [ "$curr" = "$new" ] || ( [ "$curr" = "" ] && [ "$new" = "none" ] ) ) && \
echo "> There is no need to switch system" || switchsystems "$curr" "$new"
[ "$new" = "none" ] && echo "No bootloader update" || updatebootloader "$new"
[ "$1" = "" ] && reboot
##[ "$1" = "" ] && [ "$new" = "none" ] || reboot
cd "$dir"
Jak to działa ? Na dwa magiczne sposoby. Po pierwsze Może być odpalone poprzez podanie parametru newsys=nowysystem w zmiennej append w lilo.conf i wtedy jest wywolywany przez rc.local, lub poprzez setsys z palca.
Krótki opis. Po pierwsze nawza systemu jest rownoczesnie nazwą katalogu w /mnt/big/SYSTEMY. W tym katalogu znajdują sie 2 pliki: systems.list i current_system o ile current_system zostanie utworzony automatycznie, o tyle zawartośc systems.list trzeba sobie samemu stworzyć. Są w nim zawarte nazwy systemów, a więc katalogi w których sie ona znajdują. W current_system znajduje się nazwa systemu obecnie znajdującego sie w katalogu glownym hda1, jesli pliku nie ma, lub jest pusty, to przyjmowany jest automatycznie brak systemu
Przykład:
ls -al SYSTEMY
drwxr-xr-x 6 root root 232 mar 22 07:41 .
drwxr-xr-x 27 root root 800 mar 22 12:53 ..
drwxr-xr-x 2 root root 168 mar 22 12:52 aurox-10.1
-rw-r--r-- 1 root root 10 mar 22 12:52 current_system
drwxr-xr-x 20 root root 632 mar 22 12:52 mandrake-10.1
drwxr-xr-x 15 root root 480 mar 22 07:47 slackware-10.1
drwxr-xr-x 20 root root 600 mar 22 07:06 suse-9.2
-rw-r--r-- 1 root root 49 mar 22 07:29 systems.list
cat systems.list
aurox-10.1
mandrake-10.1
suse-9.2
slackware-10.1
cat current_system
aurox-10.1
Jasne ? Ok. Idziemy dalej.
W katalogu /mnt/big/SYSTEMY/nazwa muszą się znajdować 3 pliki bootloader (wykonywalny), postmove (wykonywalny) i system.list (zawiera wszystkie katalogi i pliki nalezace do systemu, nie moga sie tam znaleźć 3 wymienione ani katalog '.' i '..' )
Przykład:
cat system.list
.mozilla
.reiserfs_priv
.rnd
bin
boot
dev
etc
home
initrd
lib
mnt
nohup.out
opt
proc
root
sbin
sys
tmp
usr
var
Plik postmove jes wykonywany za każdym razem, gdy przenoszony jest system, parametrami przekazywanymi do niego sa kolejno: nazwa systemu, katalog zrodlowy, katalog docelowy i wartosc install/uninstall, w zaleznosci, czy jest wrzucany do swojego katalogu, czy do katalogu glownego partycji. Tak to wygląda w skrypcie:
$mountpoint$subdir/$1/postmove "$1" "$mountpoint" "$mountpoint$subdir" "uninstalling"
$mountpoint$subdir/$2/postmove "$2" "$mountpoint$subdir" "$mountpoint" "installing"
przykładowy plik:
#! /bin/sh
rm -f halt .bash_history 2> /dev/null
rm -rf .mc 2> /dev/null
Plik ten jest zawsze wywoływany po zmianie katalogu na katalog z ktorego system zostal przeniesiony. Akurat ten przykład nie wykorzystuje zadnego parametru, ale jest mozliwośc wykazania sie fantazją. Ten skrypt słuzy akurat do sprzątania po single mode (telinit 1).
Plik bootloader jest odpowiedzialny za załadowanie lilo do bootsektora hda1. Nie są mu przekazywane zadne parametry
skrypt:
updatebootloader() { ## systemname
echo "Updating bootloader ..."
$mountpoint$subdir/$1/bootloader
}
plik spod suse:
#! /bin/sh
chroot /mnt/big/ /sbin/lilo
plik spod auroxa:
#! /bin/sh
/sbin/lilo -C /mnt/big/SYSTEMY/aurox-10.1/lilo.conf
Słowko komentarza Aurox, uposledzony pod tym względem nie ma własnego lilo, ale co z tego, skoro lilo ma szlaczek, ktory caly ten cyrk nadzoruje. Suse ma włase i o ile uda się zainstalować oryginalne warto probować, bo i samo lilo i libdevmapper mogą się różnic w zaleźnosci od systemu, stąd zreszta chroot.
Aha, no tak w katalogu Auroksa są 4 pliki ktore nie należ do systemu (dodatkowe lilo.conf), ale ta sprawą zajme sie poźniej. W każdym razie poki co warto zapamietać, że skrypt nie widzi plików nie wymienionych w system.list.
przy okazji wrzucę te własnie pliki konfugracyjne, dla pokazania różnic pomiedzy konfiguracją lilo z wnętrza i z zewnątrz systemu :
SuSE z wnętrza systemu przez chroot (/mnt/big/SYSTEMY/suse-9.2/etc/lilo.conf) :
message = /boot/message
timeout = 40
prompt
default = SuSE-9.2
boot = /dev/hda1
image = /boot/vmlinuz
label = SuSE-9.2
#initrd = /boot/initrd # mam przekompilowane jajko i juz nie potrzebuje initial ramdusk'u
optional
root = /dev/hda1
vga = 0x317
append = "quiet selinux=0 splash=verbose resume=/dev/hda2 showopts desktop elevator=as resume2=/dev/hda2"
image = /boot/vmlinuz
label = SuSE-9.2-fail
#initrd = /boot/initrd
optional
root = /dev/hda1
vga = 0x317
append = "showopts ide=nodma apm=off acpi=off noresume selinux=0 barrier=off nosmp noapic maxcpus=0 3"
image = /boot/memtest.bin
label = Memory_Test
vga = 0x317
optional
append = ""
Aurox z zewnątrz systemu (/mnt/big/SYSTEMY/aurox-10.1/lilo.conf)
prompt
timeout=50
default=linux.new
boot=/dev/hda1
map=/mnt/big/boot/map
install=/mnt/big/boot/boot.b
##message=/mnt/big/boot/message
lba32
image=/mnt/big/boot/vmlinuz-2.6.9-10.1.aur.4
label=linux.old
initrd=/mnt/big/boot/initrd-2.6.9-10.1.aur.4.img # oryginalne jajko
read-only
vga=791
root=/dev/hda1
append="quiet resume2=/dev/hda3 resume=dev/hda3"
image=/mnt/big/boot/vmlinuz-2.6.9-10.1.aur.4custom
label=linux.new
read-only
initrd=/mnt/big/boot/initrd-2.6.9-10.1.aur.4.img
# tu też mam przekompilowane jajko, ale cham nie widzi konsoli bez tego, potem się tym zajmę
vga=791
root=/dev/hda1
append="quiet resume2=/dev/hda2 resume=dev/hda2"
Na pierwszy rzut oka widać różnicę, w scieżkach dostępu do jajka (vmlinuz) i ramdysku (initrd) i innych plików
Jak działa skrypt ? Pomine takie rzeczy jak zapamietanie i odtworzenie sciezki, w ktorej sie znajdujemy (dir=pwd
), to są szczegóły, ktore nie powiedzą nic komuś, kto nie wie jak sie programuje w shella, a są zbyt oczywiste, dla tych, którzy tego programowania lizneli. Skrypt najpierw sprawdza, czy został wywołany z palca z parametrem (nazwą systemu do ustawienia), czy poprzez skrypt inicjacyjny. Proste, jesli parametry przekazane poprzez append z lilo zawierają ciąg 'newsys=' i $1 (czyli parametr wywolania) jest pusty, to jest to wywołanie systemowe. O tym jak przygotowac lilo, do przekazywania tych parametrów będzie oczywiście dalej. Jak pobrać ten parametr ? patrzcie wyzej jest tam coś takiego:
append="quiet resume2=/dev/hda2 resume=dev/hda2". Ano poprzez /proc/cmdline. Znajdzcie ten ciąg w skrypcie i już wiadomo o co biega. Program awk lub cut (jak widać nie zdecydowalem sie na cut'a) może służyć jako parser linii. Wcześniej sprawdzane jest istnienie pliku current_system, ewentualne tworzenie go i pobieranie nazwy aktualnego systemu. Potem nastepuje sprawdzenie czy system padany w ten, czy inny sposób znajduje sie w ogole w pliku systems.list. Podprogram checksystem() sprawdza, czy wszyskie pliki z system.list znajdują sie na swoim miejscu. Najpierw ta operacja wykonowana jest dla $curr, czyli aktualnego systemu, potem w podprogramie checkothers() sprawdzana jest reszta z pozycji listy systemów. Potem nastepuje zamiana systemow, w tym momencie dochodzi możliwośc realizacji parametru none. Może się to przydać, gdy chcemy postawić nowy system. Wywołanie 'setsys none' spowoduje przerzucenie aktualnego systemu do SYSTEMY, natomiast nie powoduje wrzucanie jakiegokolwiek do katalogu głównego. Możliwośc zwolnienia maiejsca pod nowy system. Po wykonaniu zadania skrypt wywołuje reboot. Są przygotowane 2 mozliwości dla ktorych to zachodzi:
[ "$1" = "" ] && reboot
Wtedy, gdy skrypt nie byl urucomiony z palca, za każdym razem (czyli parametr byl przekazany przez newsys, a nie przez linie polecen). Lub (aktualnie zakomentowana możliwość, do wyboru jedna czy druga, druga daje mozliwośc zalogowania do systemu, po wykonaniu skryptu)
[ "$1" = "" ] && [ "$new" = "none" ] || reboot
Wtedy, gdy nie dośc, że był uruchomiony przez skrypt startowy, to jeszcze newsys nie bylo ustawione na none.
Jeszcze jeden parametr wywołania --update-bootloader. Nie podmienia systemów. Tylko uruchamia skrypt bootloader dla aktualnego systemu.
Skrypt pisałem tak, aby przy zajsciu jakiegokolwiek błedu przerwał pracę.
Ok. Myslę, że wszystko co się wiąże ze skryptem opisałem.
Ufff. To był chyba najdłuższy i najcięższy do opisania i wytłumaczenia kawałek. Jeśli mi sie nie udało, albo jeśli czegoś nie jesteście pewni, w żadnym wypadku sie nie bierzcie za robotę, bo możecie coś powalić. Kto pyta nie błądzi.
::::: Prawie ostateczny konfig
Mamy 2 systemy na hda1 i jeden główny na hda3. Oba systemy powinny aktualnie siedzieć grzecznie w katalogu SYSTEMY i czekać. Jesli sami nie potraficie stworzyć pliku SYSTEMY/systems.list, to gotowa recepta:
ls /mnt/big/SYSTEMY | grep -v systems.list > /mnt/big/SYSTEMY/systems.list
Potem trzeba ten plik wyedytowac i wyrzucic z niego wszystko, co nie jest katalogiem i nie zawiera wewnatrz systemu. Jesli szliscie dokłądnie wg. tego co pisałem, to powinniscie mieć w tej chwili między innymi takie wpisy :
nasz_nieokrojony_system
nasz_system
Jeśli cos więcej, to wywalacie, pozostają tylko te 2.
Przyszedł czas na system.list wewnątrz każdego katalogu:
ls /mnt/big/SYSTEMY/nasz_nieokrojony_system | grep -v system.list > /mnt/big/SYSTEMY/nasz_nieokrojony_system/system.list
ls /mnt/big/SYSTEMY/nasz_system | grep -v system.list > /mnt/big/SYSTEMY/nasz_system/system.list
Edytujecie i wywalacie wszytko, co nie należy do tego systemu. W szczególności katalogi '.', '..' oraz ewentualne inne pliki, ktore sami wrzuciliscie w miedzyczasie (bootloader/postmove).
Pliki bootloader:
Macie powyżej przykład takiego pliku, łacznie z lilo i wyszczególnieniem, jak sie to robi dla systemu posiadajacego i nie posiadającego lilo. Jeśli nie używacie redhata i pochodnych, to prawdopodobnie jesteście w sytuacji jaką pokazałem na przykładzie SuSE. Wystarczy przekopiować wtedy ten plik. Nad systemami, kore lilo nie maja trzeba troszkę samemu posiedzieć i przekonwertować gruba do zjadliwej dla lilo papki, a potem użyć skryptu jaki pokazałem na przykładzie Auroksa.
Pliki postmove:
Fantazja dowolna Ten ktory pokazałem wyżej jest jednak calkowicie wystarczający.
Prawa. Potrzeba aby postmove i bootloader były wykonywalne.
wchodzimy do kazdego z katalogów (/mnt/big/SYSTEMY/nasz_system i ls /mnt/big/SYSTEMY/nasz_nieokrojony_system) i wpisujemy :
'chmod 700 bootloader ; chmod 700 postmove'
Pierwsza cyferką (owner) musi byc 7, no ewentalnie 5 lub 1 (bit o wartości dec 1 jest odp za pozwolenie uruchomienia, wskazuje na plik wykonywalny - zazwyczaj zielony z gwiazdka pod mc), druga (group) i trzecia (others) - 0 jest rownie dobra jak cokolwiek innego. Ważne aby bit odpowiedzialny za 2 nie byl zapalony (2 - zapis/kasowanie). 4 jest w miarę neutralne. Wiec możecie sobie zmienic na np. 744, albo 755 (i tak inni nie beda mogli przerzucic plikow należących do roota). Skoro 1 to uruchomienie, 2 zapis, to 4 musi byc odczytem, suma tworzy łączne prawa.
:::::. Testy.
Najpierw z konsoli. Wklepujemy samo setsys. Powinno wywalić cos a'la help, error i ostrzeżenie, że z systememi nie ma zabawy. Ok. tak ma być. Skoro nie ma żadnego systemu, to teraz robimy cos takiego: 'setsys nasz_system' i patrzymy, czy nie wyskoczył jakis błąd. W tej chwili nasz_system (pisalem, przyda sie do testow) powinien byc w /mnt/big i powino sie zainstalować lilo. Next step: 'setsys none'. Dziala ? No i na koniec zostawiamy sobie, jeśli do tej pory wszystko bylo dobrze: 'setsys nasz_nieokrojony_system' i 'setsys --update-bootloader'
Dobrze. Wszystko działa z konsoli. A jak ma działać z lilo? Po prostu wrzucę tu swój plik, sami juz do tego dojdziecie, bo trąbiłem co i raz.
boot = /dev/hda
prompt
timeout = 10
change-rules
reset
vga = 791
default = Linux
image = /boot/vmlinuz
root = /dev/hda2
label = rescue
append = "quiet"
read-only
other=/dev/hda1
label = Linux
optional
other=/dev/hda
label = -------------
image = /boot/vmlinuz
root = /dev/hda2
label = mandrake-10.1
append = "quiet newsys=mandrake-10.1"
read-only
image = /boot/vmlinuz
root = /dev/hda2
label = aurox-10.1
append = "quiet newsys=aurox-10.1"
read-only
image = /boot/vmlinuz
root = /dev/hda2
label = suse-9.2
append = "quiet newsys=suse-9.2"
read-only
image = /boot/vmlinuz
root = /dev/hda2
label = slackware-10.1
append = "quiet newsys=slackware-10.1"
read-only
image = /boot/vmlinuz
root = /dev/hda2
label = none
append = "quiet newsys=none"
read-only
image = /boot/vmlinuz
root = /dev/hda2
label = bootloader
append = "quiet newsys=--bootloader-update"
read-only
Uruchomienie jednego z dużych systemów następuje po wyborze Linux, lilo wtedy załaduje i uruchomi bootloader z bootsektora hda1. Po wyborze ktorejkolwiek z innych opcji zostanie załadowany mały system i nastapi zmiana systemu na przekazany poprzez zmienną newsys. Pozycja '--------' to nic innego jak graficzny dinks oddzielajacy, po jego wyborze lilo sie tylko przeładuje.
:::::: Instalowanie i usuwanie systemów. Uwagi koncowe
Aby zainstalowac system trzba aktualny schować do jego katalogu, czyli wybrać bądź z menu lilo badz z palca opcje 'none' (po to ona powstala). Następnie przy instalacji trzeba pamiętac o kilku prostych rzeczach:
- Nie zdawać się na automatyczne partycjonowanie, nie kasować partycji, jedynie ustawiać ich punkty montowania.
- Za żadne skarby nie formatować partycji, bo stracicie wszystko co do tej pory zainstalowaliście.
- Nigdy nie instalować bootloaderów w MBR, jesli nie mozna zainstalować w bootsektorze (hda1), nie instalować w ogóle. Przykładów na konfiguracje lilo dalem aż nadto, więc nie powinno bć problem z ręczną konfiguracją.
Jesli sie zdarzy nieszczęście i jednak zamażecie MBR, to macie w bootsektorze hda3 kopie lilo. Wystarczy wtedy dopisać do lilo.conf zaladowanego systemu coś takiego:
other=/dev/hda3
label = SmallSys
i przeinstalować lilo, albo jesli /dev/hda3 jest zamontowane w /mnt/hda3 mozna wykonać 'chroot /mnt/hda3 /sbin/lilo'
Usunąc dany system, jest bajecznie prosto :) Nie moze byc systemem aktualnym, trzeba najpierw wrzucic go do katalogu ('setsys none' lub 'setsys innysystem'), potem usunąc katalog (rm -rf) i usunąc wpis z pliku system.list. Wszystko.
Na zakończenie chciałem jeszcze dopisać, że nie warto w żadnym systemie montować w ogóle hda3 (wywalić to z fstab'a), bo to tylko cos koło 80 MB, z czego wolnego tam może być koło 15 MB. Poza tym system nie zamontowany jest odporny na blędy zapisu, zniszczenie dziennika/jurnalu przy twardym resecie i tym podobne.
::::::. Koniec
Mi to działa :))<url>
stary ailowiu
błędy ortograficzne!
Z popularnych Redhatów jedynie CentOS ma lilo w standardowej dystrybucji, u reszty na cd/dvd tego nie uświadczysz. Albo instalacja z mirrora (ftp/http/dysk/co tam jeszcze oferuje jako żródło), albo własnoręczne sciągnięcie i instalacja lilo. Poza tym instalacja systemu w komputerze domowym, czy notebooku, na więcej niż jednej partycji, często mija się z celem. Inna sprawa, gdy system jest przeznaczony na serwer, inna na biurko.
Masakra... Zabójczy artykuł po prostu :]. A jak chodzi o zastosowanie? Nie wiem, czy przydatne, wszak polecane jest tworzenie kilku partycji dla jednego systemu, nie na odwrót :D (tak twierdzi przynajmniej mój stryjek, który bądź co bądź w unixie pracuje zawodowo od dawna i na tej zasadzie oparte są wszystkie instalacje Linuxów na moich kompach). Ale fakt, często się przydaje kilka różnych systemów. Sam niedawno miałem 3 różne RedHaty zainstalowane na jednym kompie :].
Jednej rzeczy się tylko przyczepię: Napisałeś, że systemy Red-Hato podobne nie mają Lilo. A ja z Lilo korzystałem przez wiele lat, zawsze mając RedHaty (i tam lilo jako domyślny bootloader).
Dobrze wiedziec ze sa tez normalni ludzie na tym swiecie ktorzy pisza ladne artykuly ;) Mimo ze jest ciekawy i az chcialbym sprobowac to nie widze wiekszego zastosowania tego bo po co mi 10 systemow? :> Oczywiscie 6! ;)
Zrobiłem Ci trochę poprawek, takich "z grubsza".
http://qyon.satanbsd.org/bin/flabra_art_diff.txt
Kiedys poprawie literowki, pomyłki i plątnie sie w zeznaniach... Pisalem to wszystko w ciągu 3h. Więc z góry proszę o wyrozumiałośc. ort! co mam inną robotę ... Dzis wymienilem mojego celeronka 400 na coppermajna 733, płytę również i w związku z tym bedę musial przeinstalować parę systemów :)
Właśnie... Ktoś potrzebuje może celerona 400 z płytą chaintecha 6BTA3 ? (bardzo zacna płyta, z najnowszym biosem, magistrala 133MHz, es1371 = SB ave 64 na pokladzie, widzi dyski do 128GB, tylko właśnie coppermina juz nie obsłuży bez specjalnej przejściówki, czyli w sam raz na jakiś nixowy serwerek)
bez sensu, ale dzięki
Od "a więc" i "no więc" też się nie zaczyna :P
Maniak i tyle... A mnie zarzucają, że dziwny jestem :) Ocena oczywista 6