Blog archive 2011

Obnova grub2 ve Fedoře 16 po instalaci Windows

Dec| 6 2011

Tuhle pohádku zná snad každý linuxák, který někdy zatoužil po dual bootu s M$ Windows. Po instalaci oken mu zbude mašina poslušně bootující pouze M$ operační systém, protože ten při instalaci bez mrknutí oka přepsal bootovací partišnu a tím i zavaděč grub.

Jak obnovit grub 1 se dočtete například zde. Ve Fedoře 16 již ale konečně najdeme grub 2, ovšem k mému nemilému předkvapení není jednoduché tuto novější verzi dostat zpátky. Nyní nabízím postup, který nakonce zafungoval:

  • seženěte si, vypalte (nebo nahrajte na USB disk) a nabootujte nějaký linux s grub 1 (např. Fedora 15)
  • zalogujte se jako root:
  • $ su -
  • spusťte interaktivní grub:
  • # grub
  • najděte svojí boot partišnu:
  • grub> find /grub/stage1
  • řekněme, že předchozí příkaz vyhodil (hd0, 0)
  • grub> root (hdx, y), tedy v našem případě root (hd0, 0)
  • grub> setup (hdx), tedy v našem případě setup (hd0)
  • po restartu by již měl být funkční grub verze 1, tedy můžeme nabootovat do původní Fedory 16
  • zalogujeme se opět jako root a obnovíme grub 2:
  • $ su -
  • # /sbin/grub2-mkconfig -o /boot/grub2/grub.cfg
  • # /sbin/grub2-install /dev/sda

V tuto chvíli s trochou štěstí máme obnovený grub2, který již ví o všech nainstalovaných operačních systémech, resp. verzí kernelu, stejně jako o nově nainstalovaném Windows.

Cest, jak dosáhnout stejného výsledku, je samozřejmě mnoho, zde uvádím jednu, která po dlouhém bádání zafungovala u mě, přičemž přímořařejší varianty selhaly.




Windows ve stylu Gnome

Dec| 6 2011

Vizualizace linuxu do podoby Windows je už celkem stará záležitost, ať již KDE nebo jiné prostředí se do podoby Windows XP nebo nově i Windows 7 stylizuje docela často. Nyní máme ale možnost udělat to i obráceně - nastylovat Windows do podoby Gnome. Celé divadlo obstará skin Gnome, odkazy naleznete zde. Nevidím v tom sice nic praktického, ale nejednoho linuxáka nuceného nějakou vyšší mocí pracovat v oknech tato možnost jistě potěší. Každopádně jako recese je to rozhodně zajímavé.

Tags: Grafika | Linux | Operační systém



Upgrade Fedora 15 na Fedora 16

Nov|10 2011

Krátká zpráva o právě provedeném upgradu operačního systému Fedora 15 na několik hodin nový systém Fedora 16. Pokud se chcete pustit do upgradu, není špatné pamatovat na několik věcí. Berte, prosím, tento text jako popis mých kroků, ne jako návod - nechci nést zodpovědnost za případné problémy s tím vzniklé.

Nebudu zdůrazňovat nutnost zálohovat data, protože upgrade je vždy riskantní operace, přestože je ze strany distribuce podporována. Je na uvážení každého, jaká data může případně postrádat, ať již je ztratí při upgradu nebo jiným způsobem. Podpora ze strany distribuce se navíc týká pouze upgrade z N na N+1, neboť přechod přímo z N na N+2 již podporován není, alespoň co se týká Fedory. Nicméně neznamená to, že je to nemožné, jen to nemusí jít tak hladce.

Na stránkách Fedora projektu je uveden postup, jak upgrade provést, šel jsem podle něho a doplnil pár kroků:

Krok 1: nabootovat do runlevelu 3 a přihlásit se jako root

Místo přechodu do konzole pomocí ctrl + alt + F2 jsem přímo nabootoval do runlevelu 3 - tedy můžeme buďto provést ln -s /lib/systemd/system/runlevel3.target /etc/systemd/system/default.target nebo přidat znak "3" nakonec příkazu v grubu.

Krok 2: importovat klíč F16 a updatovat yum

rpm --import https://fedoraproject.org/static/A82BA4B7.txt yum update yum yum clean all

Krok 3: provést samotný update

yum --releasever=16 --disableplugin=presto distro-sync

Tato operace trvá dlouho. Záleží na počtu nainstalovaných balíčků a rychlosti stahování. Upgrade cca 1600 balíčků mi například zabral hodinu a půl času.

Krok 4: instalace nového grub2

/sbin/grub2-mkconfig -o /boot/grub2/grub.cfg /sbin/grub2-install /dev/sda

Fedora 16 má konečně grub2, nicméně ten není po upgradu nainstalován na MBR. Pro instalaci na /dev/sda jsem to napravil výše uvedeným způsobem.

Krok 5: relabel a reboot

touch /.autorelabel reboot

Po upgradu bylo potřeba re-labelovat SELinux kontext celého systému, protože se může stát, že některé soubory mohli (a také měly) kontext špatný. V mém případě například nebylo možné přihlásit se do gnome a najít důvod tohoto problému mi zabralo zhruba půl hodiny. Relabel celého systému trvá samozřejmě dlouho, můj 300 GB filesystem (kde ale mnoho souborů má několik GB) byl přelabelován za zhruba 10 minut.

Suma sumárum dvě hodinky práce. Oproti čisté instalaci, která zabere zhruba třetinu času, mám ale všechny potřebné balíky již na svém místě a konfigurace zůstala zachována.

Tags: Linux | Fedora | Operační systém



Aktivace "on demand" v systemd

Nov| 2 2011

Výraz bootovací sekvence vychází z dřívější implementace spouštění služeb (doby SysV a prakticky i Upstart), kdy se jednotlivé služby staticky seřadily podle priorit spouštění a init systém je při bootu spouštěl v daném pořadí, pěkně jednu po druhé. Důsledkem toho nebyla výjimkou situace, že zpoždění jedné služby mělo za následek zpoždění celého bootu, nehledě na to, že díky mnoha systémových volání se procesor během bootu často nudil a pouze čekal na nějakou I/O operaci.

Upstart sice dokázal přidat částečnou paralelizaci, nicméně závislosti mezi službami zůstaly lineární. Revoluci v tomto přináší až systemd. Jeho autoři si položili otázku, proč vlastně na sebe služby závisí a zda je skutečně potřeba mít spuštěnu celou službu, předtím, než začneme spouštět službu druhou, která na ni závisí. Zjistili, že v podstatě vše závisí na komunikačních kanálech, konkrétně socketech, dbus sběrnici, apod. Pokud dokážeme mít daný komunikační kanál k dispozici již dříve, není nutné čekat na spuštění celé služby a můžeme vesele spouštět další.

Vezměme si například službu komunikující s NetworkManagerem pomocí dbus. systemd ví, jakým komunikačním kanálem (v případě dbus object path, nicméně můžeme si místo toho představit např. unix socket) tyto dvě služby komunikují a tento kanál dopředu vytvoří. Daná služba se startuje paralelně s NetworkManagerem a může vesele zapisovat do kanálu, aniž by se jakákoliv zpráva ztratila. Až ve chvíli, kdy potřebuje z tohoto kanálu číst, dochází k případnému zastavení, což nicméně odpovídá běžnému čekání na I/O operaci.

Startování služeb pomocí systemd navíc navíc nabízí tzv. start na požádání, kdy služby nejsou spouštěny v případě, že zatím nejsou potřeba. Můžeme danou službu nadefinovat tak, že bude spouštěna až v případě, že s daným kanálem (např. socketem) začne někdo komunikovat. V tomto případě je ovšem nutné si uvědomit, že start a inicializace některých služeb trvá déle a je tedy nutné počítat s určitým zpožděním. Na druhou stranu služby jako cups, kde zpomalení v řádu sekund nehraje roli, je ideálním kandidátem na spouštění pomocí socket aktivace. Démon cups tak neběží ihned po startu systému, ale spouští se až v době, kdy chce uživatel tisknout.

Následuje ukázka jednoduché služby předpovědi počasí. Služba bude naslouchat na portu 8289 a přijímat requesty ve formátu YYYY-MM-DD. Odpovědí bude předpověď počasí na tento den. Pokud chceme takovou službu vytvořit a používat se systémem Upstart nebo obdobným init systémem, musíme do serveru implementovat minimálně:

  • funkci pro zpracování dotazů a vrácení výsledku
  • démonizaci (obdobný proces v mnoha aplikacích = duplicita kódu)
  • inicializaci socketu pro komunikaci
  • navázání tohoto socketu na port 8289
  • vytváření procesů pro jednotlivé requesty pro zajištění paralelního zpracování dotazů
  • vytvoříme init script například zkopírováním základu z jiné služby (duplicita kódu)

Často si chceme být navíc jisti, že pokud náš démon spadne, bude vždy znova spuštěn, takže vytvoříme chůvičku -- jednoduchý program, který obalí našeho démona, hlídající jeho případný kolaps.

Pomocí systemd je situace značně jednodušší. Pokud nám stačí podpora systemd, necháme si socket vytvořit jím a přesměrujeme stdin/stdout na tento socket.

Seznam kroků, které budeme muset implementovat, se tedy změní na:

  • funkci pro zpracování dotazů a vrácení výsledku
  • dotaz přečteme z stdin a odpověď zapíšeme do stdout
  • vytvoříme unit soubory pro službu (12 řádků) a unit soubor pro socket (8 řádků)

systemd se umí postarat o znovu-spuštění démona v případě pádu (pokud si to přejeme), vytvořený socket správně naváže na port a v našem případě (služba se spouští rychle) spustí novou instanci procesu pro každé příchozí spojení na daném socketu. systemd si démonizační proces obstará sám a program je navíc implementován pro běh na popředí, což umožňuje snadnější ladění.

Pokud vynecháme funkci, která zpracovává dotazy a vrací do odpovědi, celý program je velmi jednoduchý:

char req[BUFFSIZE], resp[BUFFSIZE];
/* get requests and leave when request = q|quit */
while (fgets(req, sizeof(req) - 1, stdin) != NULL)
{
  if (strncmp(req, "q", 1) == 0 || strncmp(req, "quit", 4) == 0)
    return;
  process_request(req, resp);
  printf(resp);
  fflush(stdout);
}

Unit soubory jsou při instalaci ukládány v /lib/systemd/systme. Adresář /etc/systemd/system slouží pro unit soubory, které jsou lokálně upraveny, stačí jen zkopírovat unit soubor z /lib do /etc a nový soubor bude po reloadu systemd démona upřednostněn. Konfigurace služby pro démona uvedeného výše může být následující:

[Unit]
Description=Forecast daemon
After=syslog.target network.target
Requires=forecastd.socket

[Service]
ExecStart=/home/hhorak/Dropbox/forecastd
StandardInput=socket
StandardOutput=socket
StandardError=syslog

[Install]
WantedBy=multi-user.target
Also=forecastd.socket

Konfigurace socketu pro výše uvedenou službu potom bude následující:

[Unit]
Description=Forecast Daemon Socket

[Socket]
ListenStream=8289
Accept=yes

[Install]
WantedBy=sockets.target

Po provedení systemctl daemon-reload a spuštění socketu pomocí systemctl start forecastd.socket, můžeme pomocí netstat -a | grep 8289 vidět, že systém naslouchá na portu 8289. Pokud se například programem telnet připojíme k danému portu, systemd spustí program forecastd, se kterým můžeme komunikovat jako s démonem.

Tags: Internet | Programování | Vývoj | Linux | Fedora | Operační systém



Běžná práce se systemd

Oct|26 2011

Stejně jako v předchozích variantách service managerů existuje i v systemd program, pomocí kterého se služby spouští, zastavují, restartují nebo se načítá jejich konfigurace za běhu. Pro tyto a další úkony slouží aplikace systemctl:

Spuštění služby, pokud již běží, nic se neděje:

systemctl start mysqld.service

Zastavení služby, pokud je již zastavena, nic se neděje:

systemctl stop mysqld.service

Restart a podmíněný restart služby; drůhý z uvedených bude proveden pouze pokud služba běží, tedy nespustí zastavenou službu, jako by to udělal první z nich:

systemctl restart mysqld.service
systemctl try-restart mysqld.service

Znovu-načtení konfigurace:

systemctl reload mysqld.service

Spouštět službu na defaultních runlevelech po startu:

systemctl enable mysqld.service

Nespouštět službu automaticky po startu:

systemctl disable mysqld.service

Zjištění, zda je služba automaticky spouštěna po startu:

systemctl is-enabled mysqld.service

Přepnutí do runlevelu 3:

systemctl isolate multi-user.target
systemctl isolate runlevel3.target

Přepnutí do runlevelu 5:

systemctl isolate graphical.target
systemctl isolate runlevel5.target

Výpis všech služeb a jejich stavů:

systemctl list-units

Znovu-načtení konfigurace démona, důležitý krok po úpravě unit souborů:

systemctl daemon-reload

Pro zpětnou kompatibilitu systemd podporuje i dřívější způsob provádění těchto operací - tedy pomocí programů service, chkconfig apod., nicméně preferovaná je novější varianta.

Pokud jste si vyzkoušeli například příkaz systemctl enable, všimli jste si, že systemd hojně pracuje se symbolickými odkazy. Například instalace služby po startu znamená přidání symbolického odkazu na příslušný service file do adresáře cíleného runlevelu, který končí příponou "target". Pokud pochopíte tento celkem jednoduchý princip, nic vám nebrání vytváření vlastních symbolických odkazů manuálně, tedy bez programu systemctl.

Jak ze systemd dostat více informací

Pokud se dostanete tak daleko, že bude te upravovat nějakou službu, například její unit soubor, případně vytvářet službu novou, bude se vám hodit trochu ukecanější systemd. To v GRUBu zařídíme přidáním následujících parametrů do příkazu načtení jádra:

systemd.log_level=debu systemd.log_target=kmsg

v případě GRUB 2 můžeme nastavit proměnnou v souboru /etc/default/grub:

GRUB_CMDLINE_LINUX="systemd.log_target=kmsg systemd.log_level=debug"
Tags: Programování | Počítače | Vývoj | Linux | Fedora | Operační systém



Démonizace po startu a zrychleni bootování

Oct|25 2011

V jednom z předešlých dílů seriálu jsem se zmínil o PID a PPID nově spuštěných procesů. Pokud spouštíme démona, chceme ho vyvázat ze stromu procesů, aby nebyl nijak ovlivněn procesem, který ho spustil. Tomu říkáme démonizace, přičemž je dobré změnit i aktuální pracovní adresář a ignorovat signály týkajicí se práce v terminálu. Ukázkovou démonizaci můžeme vidět na následujícím kódu, který je vypůjčen z implementace lighttpd, jednoduchého http serveru.

signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
if (0 != fork()) exit(0);

if (-1 == setsid()) exit(0);

signal(SIGHUP, SIG_IGN);

if (0 != fork()) exit(0);

if (0 != chdir("/")) exit(0);

Jak vidíme, klasická démonizace navíc obsahuje tzv. double-fork, tedy celkem dvakrát se spouští nový proces se všemi důsledky pro výkon. Rodičovský proces vždy končí s návratovým kódem 0, což je již na první pohled neefektivní z hlediska výkonu (uvědomme si, kolikrát se daná procedura provádí během jednoho bootu), ale také nám dost znesnadňuje kontrolu inicializace démona. V mnoha případech je totiž načítání konfigurace a další inicializační činnost prováděna až v démonizovaném procesu.

Pokud inicializace selže, démon není spuštěn, nicméně rodičovský proces při démonizaci již vrátil nulový návratový kód, tedy hlásil úspěšné spuštění. Tento problém je většinou pomíjen a je pouze na init systému, aby si pomocí pid souboru dohledal, že efektivní proces daného démona již neběží a zaujal příslušná opatření.

Tam, kde by nesprávný návratový kód znamenal větší potíže, je potřeba vytvořit IPC komunikaci mezi novým procesem a původním rodičem, což přináší další nemalé zásahy do kódu démona. Využít můžeme například dbus nebo komunikaci pomocí socketů, nicméně asi cítíme, že to všechno by bylo docela zbytečné, pokud bychom měli lepší způsob, jak se vyvázat z terminálu, resp. od rodičovského procesu.

systemd a démonizace

Nejnovější implementace procesu init spatřilo světlo světa v roce 2010 a jmneuje se systemd. Označení init systém vychází z historického označení systémů sysvinit, proto se pokusím nadále používat obecného označení systémový manažer a manažer služeb (system and service manager).

systemd dokáže používat i starší skripty používané pro Upstart nebo System V. Nicméně pro plné využití je doporučeno vytvořit nativní konfigurační soubory, tzv. Unit files.

Zkusme vzít například lighttpd, jednoduchou implementaci http démona. Ten používá ukázkovou démonizaci pomocí double-fork metody. systemd dokáže takovou implementaci vzít bez změn a díky své vnitřní logice pozná hlavní proces od rodičovského (v tomto případě zůstane běžící pouze jeden, přičemž rodičovské jsou ukončeny). Tento proces potom stráží a případně restartuje službu, pokud hlavní proces neočekávaně skončí. Nativní Unit file pro lighttpd se zachovanou démonizací i s definicí konfiguračního souboru pro démona vypadá následovně:

[Unit]
Description=Lightning Fast Webserver With Light System Requirements
After=syslog.target network.target

[Service]
Type=forking
PIDFile=/var/run/lighttpd.pid
EnvironmentFile=-/etc/sysconfig/lighttpd
ExecStart=/usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf

[Install]
WantedBy=multi-user.target

Všimněme si typu služby "forking", která právě definuje, že démon používá démonizaci pomocí double-fork. systemd nicméně dovoluje (a dokonce doporučuje, pokud je to možné) používat spouštění bez démonizace, tedy pouze v jednom procesu. lighttpd démon nám dovoluje spuštění na popředí pomocí přepínače -D, kdy se démonizace neprovede a můžeme tak démona snáze ladit. V případě systemd můžeme tento mód použít a místo "forking" definovat službu jako "simple", což je výchozí hodnota, takže to nemusíme do Unit souboru vůbec uvádět. Výsledný soubor tedy bude vypadat následovně:

[Unit]
Description=Lightning Fast Webserver With Light System Requirements
After=syslog.target network.target

[Service]
PIDFile=/var/run/lighttpd.pid
EnvironmentFile=-/etc/sysconfig/lighttpd
ExecStart=/usr/sbin/lighttpd -D -f /etc/lighttpd/lighttpd.conf

[Install]
WantedBy=multi-user.target

Čeho jsme docílili? Tak zejména systemd nemusí zjišťovat, který proces je výkonný pomocí pid souboru nebo jiného mechanizmu, protože je ve skutečnosti spuštěný všehovšudy pouze jeden proces. Zároveň neprovádíme démonizaci, což znamená ušetření určitého výpočetního času.

Jednoduché je i reportování či případné ukončení služby a správné vrácení návratové hodnoty v případě, že inicializace démona neproběhne v pořádku. A v neposlední řadě si můžeme (pokud by systemd byl používán na všech systémech, které používají našeho démona) ušetřit čas při programování a ladění démona. Při spuštění se o veškerou démonizaci postará systemd.

Tags: Programování | Počítače | Vývoj | Linux | Fedora | Operační systém