neděle 2. května 2010

Hrátky s Debianem

Jako technik jednoho conu jsem každoročně postaven před problém, jak zajistit na X náhodných vypůjčených počítačích zajistit alespoň trochu jednotné softwarové prostředí. Když se tím člověk nezabývá, tak to dopadne blbě - třeba tak, že přijde přednášející s prezentací, kterou počítač neotevře. Já již několik let jako základ používám Linux. Jiné OS by mohly být zdrojem nějakého licenčního problému, což ve stavu, kdy za technickou stránku odpovídám, rozhodně nechci. Vzhledem k mé oblibě Debianu je jako základ použit právě on.

Před dvěma lety jsem připravil relativně jednoduchým hackem systém tak, že byl na USB disku společně s daty (nějaké to video, prezentace a hromada dalších pitomin) také image systému. Fungovalo to jednoduše - Debian má hodně univerzálně pojatý initrd, který se dá velice jednoduše přegenerovat. Jediná úprava oproti defaultnímu stavu tak byla úprava skriptu, který připojuje ROOT. Úprava vypadala asi takhle:

/scripts/local:

- mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}

+ mkdir /sda
+ modprobe vfat
+ modprobe ext3
+ mount -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} /sda
+ mount -t ext3 /sda/root.ext3 ${rootmnt} -o loop

Tohle byl relativně jednoduchý hack, který neřešil hromadu věcí. Především systém po pivot_rootu z initrd neviděl /sda a mám pocit, že ho pořádně neumountoval. To samé se dělo s loopbackem systému, takže měl systém tendenci se rozbíjet. Jinak to ale fungovalo celkem dobře. Hlavně byl debootstrap, úprava skriptu a nakopírování na disk otázka chvíle. Větší problémy nastávaly s přemlouváním grubu, aby se hodil na USB Storage (Obzvlášť když do toho všeho přišel grub2).

Letos jsem se ale rozhodl nedělat všechno na poslední chvíli a podíval jsem se tomu na zoubek trochu víc (měl jsem sice ještě další důvody, ale to nechme stranou). Jedna z věcí, co se mi nelíbila na předchozím řešení byl fakt, že obraz rootu byl relativně velký (root.ext3 měl velikost asi 1.6 GB a občas byl docela problém se do toho prostoru vůbec vejít (ono když potřebujete openoffice.org, tak vám místo velice rychle mizí před očima). Vzhledem ke koncepci systému (nainstalované aplikace zůstávají stejné a jediné, co se trochu mění jsou nastavení, případně nějaké ad-hoc instalované aplikace), jsem dospěl k názoru, že bude vhodnější použít styl známý z Live CD a podobných mini-distribucí - mít základní systém komprimovaný a přes něj mít overlay s nějakým malým ext3 obrazem.

Úvahu o tom, co chci dělat, jsem měl, tak jsem se pustil od práce. Pro začátek jsem debootstrapnul systém a začal řešit, jestli jsou všechny potřebné věci v běžném jádru. Bod 1, squashfs jako vhodný komprimovaný filesystém v aktuálním jádru je (sice nemá podporu pro lzma, ale jak jsem se později přesvědčil, ta s velikostí moc neudělá). Problém ovšem nastal s virtuálním systémem, který mi udělá overlay základu a datového bloku. Moje první představa byla podívat se po unionfs. Ten se využívá velice často a očekával jsem jeho přítomnost v jádru. Naštěstí jsem brzy přišel na alternativu. Debian má v základu podporu pro "Another Union FS" (AUFS), který je obdobou unionfs. Tím mi odpadla práce s rekompilací jádra (do čehož jsem se téměř pustil, než jsem AUFS našel).

Další věc byla úprava initrd, což bylo velice jednoduché - našel jsem správný  zdroj. Skript na téhle stránce mi přišel jako dobrý základ pro systém. Pak mne napadlo, že když je základní image menší jak pul giga, tak by možná bylo dobré jej natáhnout do paměti a nebýt závislý na externím disku (to se hodí třeba na pokladně, nebo na nějakém servisním počítače). Tak jsem skript upravil tak, aby se image nakopíroval do paměti a běželo se z ní.

Tohle řešení nádherně fungovalo. Jediná vada byla, že zkopírovat půl giga z Flashky do paměti chvíli trvá a chtělo by to progress bar. Tak jsem si progress bar napsal. Není dokonalý, ale svoji funkci plní dobře. Tady je jeho kód:

#!/bin/sh
# usage cp.sh from to
BLOCK=1048576
OUT="############################################################"
OUT1="                                                            "
LEN=`du -k $1 |cut -f 1`
CNT=`expr $LEN \* 1024 / $BLOCK `
echo Copying $1 to $2
#for i in `seq 0 $CNT`; do
i=0
while [[ "$i" -le $CNT ]]; do
        dd if=$1 of=$2 bs=$BLOCK count=1 skip=$i seek=$i >/dev/null 2>/dev/null
        WA=`expr $i \* 60 / $CNT`
        WB=`expr 60 - $WA`
        echo -en "\015 ["
        [[ "$WA" != "0" ]] && echo -en `echo "$OUT"|cut -c 1-$WA`
        [[ "$WB" != "0" ]] && echo -en "`echo "$OUT1"|cut -c 1-$WB`"
        echo -en "] $i/$CNT MB"
        i=`expr $i + 1`
done
echo

Kdyby měl někdo nějaký nápad, jak ho vylepšit, tak mi dejte vědět (tohle bych celkem rád dotáhl do konce).

Momentálně chci ještě několik věcí vyřešit, ale to už jsou naštěstí drobnosti. A možná, až bude systém otestován, tak ho i vystavím :).