Portál AbcLinuxu, 4. května 2025 15:54
Stejně jako různé distribuce Linuxu, i Solaris (a OpenSolaris) pro zjednodušení instalace softwaru používá balíčkovací systém. Ten vychází ze standardu System V R.4 (SVR4) a i když co do stáří je ve srovnání s některými linuxovými balíčkovacími systémy prakticky kmetem, jeho možnosti jsou opravdu rozsáhlé. Přitom však není nijak složitý ani pro administrátora, který balíčky instaluje, ani pro vývojáře, který je vytváří.
V tomto článku se zběžně podíváme, jak balíček na Solaris nainstalovat a odinstalovat, ale hlavně, jak jej snadno a rychle vyrobit. Jak už to samozřejmě u takovýchto článků bývá, berte jej pouze jako stručný úvod a ochutnávku možností. Mnohem víc informací najdete v manuálových stránkách a v Application Packaging Developer's Guide.
Pokud chcete balíčky vytvářet, musíte je nejdřív umět instalovat a odstraňovat. Naštěstí je to v Solarisu opravdu jednoduché. Pro instalaci slouží pkgadd(1M)
, pro odstraňování ekvivalentně pkgrm(1M)
. Možná trochu neobvyklé může být, že pkgadd
očekává, že je balíček uložen v adresáři /var/spool/pkg, takže pokud ho máte někde jinde, musíte příkaz na správnou cestu navést parametrem -d device
, kde ono device znamená nejen třeba pásku, ale i normální soubor nebo adresář s balíčkem.
Solaris umí hlídat splnění potřebných závislostí mezi programy během instalace. Bohužel je stávající systém neumí automaticky naplňovat stahováním dalších potřebných závislostí z repozitářů. Počkejme si na další verzi...
Pro práci s balíčky slouží ještě několik dalších programů. Z těch nejdůležitějších jmenuji pkgchk(1M)
, který slouží pro kontrolu stavu nainstalovaných balíčků, a pkginfo(1)
, pomocí kterého můžete zjistit, které balíčky máte nainstalované a řadu podrobností o nich. Teď už se ale konečně podívejme, jak se tyto balíčky vlastně vytvářejí...
Začneme jednoduše. Chceme vytvořit balíček, který bude obsahovat nejoblíbenější demonstrační program na světě a jeho manuálovou stránku. Jeho obsahem budou dva soubory, /opt/hello/bin/hello
a /opt/hello/share/man/man1/hello.1
. Pokud se ptáte, proč jsem zvolil adresář /opt
, odpověd je snadná: je to jediné místo, kam se na Solarisu smí instalovat software, který není jeho součástí (viz [APGD]). Samozřejmě, pokud vytvoříte balíček, který bude instalovat soubory jinam, bude to fungovat a nemusíte se ani bát, že si pro vás přijde Solstapo, ale možná tím zkomplikujete situaci uživatelům, kteří na tuto
konvenci spoléhají.
Ze všeho nejdřív vytvoříme pracovní adresář a v něm soubor pkginfo
, který bude obsahovat základní informace o vytvářeném balíčku:
$ cat pkginfo PKG=ABCLhello NAME=The world famous hello world program. ARCH=i386 VERSION=1.0 CATEGORY=application BASEDIR=/opt
Opět asi netřeba podrobně vysvětlovat, co která řádka znamená, takže jen ty zajímavější věci:
PKG
je krátký název balíčku (maximálně 32 znaků). První čtyři znaky by podle specifikace měly být zvolené unikátně pro vaši firmu, Sun doporučuje například symbol akcií (což je docela dobrý nápad, který bohužel nefunguje pro ty z nás, kdo nevydáváme akcie, a pro ty z nás, kdo změnili symbol pro svoje akcie, například ze SUNW na JAVA :-)).ARCH
říká, pro kterou architekturu je balíček určen ("sparc" pro rozumné procesory a "i386" pro ty ostatní).VERSION
není specifikovaný žádný pevný formát, pouze maximální délka 256 znaků.BASEDIR
je cesta, která se použije jako základ pro adresářovou strukturu balíčku. Může se tedy stát, že by kvůli drobné chybě mohl nějaký soubor skončit na úplně jiném místě filesystému a dělal neplechu, o čemž by v CCP mohli vyprávět.Pochopitelně, pkginfo
může obsahovat ještě řadu dalších informací, ty ale zatím vynecháme. Toto je příklad skoro minimálního pkginfo
souboru, protože kromě BASEDIR
jsou všechny ostatní řádky povinné.
To, že známe název balíčku je sice super, ale bez souborů, které do něj patří, by to jaksi nebylo ono. K jejich specifikaci slouží soubor prototype
, který nejsnáze vytvoříme pomocí příkazu pkgproto
na základě existujícího adresářového stromu. Proto v našem pracovním adresáři vytvoříme strukturu odpovídající cílové struktuře adresářů a souborů nainstalovaného balíčku. Pokud všechny soubory, které chceme instalovat, mají společný prefix (jako v našem případě /opt
), vynecháme jej:
$ find . . ./hello ./hello/bin ./hello/bin/hello ./hello/share ./hello/share/man ./hello/share/man/man1 ./hello/share/man/man1/hello.1 ./pkginfo
Spustíme příkaz pkgproto
, jako parametr mu zadáme náš pracovní adresář a jeho výstup uložíme do souboru prototype
:
$ pkgproto . > prototype $ cat prototype d none hello 0755 jdoe other d none hello/bin 0755 jdoe other f none hello/bin/hello 0555 jdoe other d none hello/share 0755 jdoe other d none hello/share/man 0755 jdoe other d none hello/share/man/man1 0755 jdoe other f none hello/share/man/man1/hello.1 0644 jdoe other f none pkginfo 0644 jdoe other
První položka označuje typ souboru. Zatím vidíme pouze typy "f" nebo "d", čili běžný soubor nebo adresář. Možností je o trochu víc, povíme si o nich za okamžik. Stejně jako o druhém poli, které určuje třídu souboru, v našem případě pouze "none". Zbytek asi nepotřebuje další komentář. Jen si všimněte, že pkgproto
převzal informace o vlastnictví souboru z filesystému, takže pokud chcete, aby ve skutečné instalaci soubory patřily někomu jinému, nezapomeňte příslušné položky upravit, například takhle:
f none hello/bin/hello 0555 root staff
Kromě toho musíme udělat ještě jednu změnu, aby řádek pro soubor pkginfo
vypadal takhle:
i pkginfo
Soubor pkginfo
se totiž nakonec také octne v našem balíčku jako speciální informační soubor, proto musí být uveden v prototypu a označen speciálním typem "i".
Zkontrolujeme, že prototyp vypadá tak, jak má (třeba jestli v něm nepřebývají nějaké zapomenuté pomocné soubory, nebo jestli naopak nějaké soubory nechybějí) a můžeme se zaradovat, protože jsme na půl cesty k hotovému balíčku.
Asi nemusím příliš zdůrazňovat, že pkgproto
je pouze pomocný nástroj a že pokud chcete, nic vám nebrání prototyp balíčku vytvořit ručně; ostatně, je to jen obyčejný textový soubor. Navíc většinou v něm stejně musíte provést nějaké změny, ať už je to prostá změna vlastníka souboru, nebo složitější nastavování typů a tříd. Je to ale užitečná pomůcka pro vytvoření počáteční verze prototypu, se kterou pak dále pracujete. Pokud se rozhodnete vytvořit prototyp ručně, nezapomeňte, že cesty v něm uvedené jsou relativní, tedy bez úvodního lomítka.
A jsme skoro hotovi! Už zbývá jen jeden příkaz:
$ pkgmk -r . ## Building pkgmap from package prototype file. ## Processing pkginfo file. WARNING: parameter <pstamp> set to "deepone20071216233400" WARNING: parameter <classes> set to "none" ## Attempting to volumize 7 entries in pkgmap. part 1 -- 130 blocks, 10 entries ## Packaging one part. /var/spool/pkg/ABCLhello/pkgmap /var/spool/pkg/ABCLhello/pkginfo /var/spool/pkg/ABCLhello/reloc/hello/bin/hello /var/spool/pkg/ABCLhello/reloc/hello/share/man/man1/hello.1 ## Validating control scripts. ## Packaging complete. </classes></pstamp>
pkgmk
dělá přesně to, co byste čekali podle názvu: vytvoří balíček. Parametr -r
říká, kde je vrchol adresářové struktury, odkud bude brát soubory. Varování ve výstupu můžeme pokojně ignorovat, týkají se položek souboru pkginfo
, které jsou volitelné, a pokud je neuvedeme, pkgmk
použije rozumné výchozí hodnoty.
Náš balíček je hotov v adresáři /var/spool/pkg/ABCLhello
(pokud se vám to nelíbí, určete jiné místo pomocí parametru -d
). A jak že vypadá?
$ find /var/spool/pkg/ABCLhello /var/spool/pkg/ABCLhello /var/spool/pkg/ABCLhello/pkgmap /var/spool/pkg/ABCLhello/pkginfo /var/spool/pkg/ABCLhello/reloc /var/spool/pkg/ABCLhello/reloc/hello /var/spool/pkg/ABCLhello/reloc/hello/bin /var/spool/pkg/ABCLhello/reloc/hello/bin/hello /var/spool/pkg/ABCLhello/reloc/hello/share /var/spool/pkg/ABCLhello/reloc/hello/share/man /var/spool/pkg/ABCLhello/reloc/hello/share/man/man1 /var/spool/pkg/ABCLhello/reloc/hello/share/man/man1/hello.1
Pokud jste zvyklí na linuxové balíčky, možná jste překvapeni. Ano, solarisový balíček není jen jeden soubor, ale celá adresářová struktura s hejnem souborů, dokonce jeho podadresář reloc
obsahuje doručované soubory s přesně takovým obsahem a na přesně stejné relativní pozici (vzhledem k BASEDIR
), jak budou vypadat po instalaci.
Ono to má své výhody: informace o balíčku jsou snadno dostupné, můžete je zpracovávat standardními unixovými nástroji, do balíčku je prostě snadno vidět. Pochopitelně, v některých případech je pohodlnější, když je balíček jen jeden velký, pokud možno komprimovaný soubor. Proto
Solaris zná druhý formát balíčku, takzvaný datastream format (tomu prvnímu se říká file system format), a je mezi nimi možno libovolně překládat příkazem pkgtrans
:
$ pkgtrans -s /var/spool/pkg /tmp/ABCLhello.pkg ABCLhello Transferring <ABCLhello> package instance $ ls -l /tmp/ABCLhello.pkg -rw-r--r-- 1 jdoe other 61440 Dec 16 23:49 /tmp/ABCLhello.pkg
-s
říká, že chceme konvertovat do datastream formátu, druhý a třetí jsou zdrojová a cílová lokace, v tomto případě je zdroj adresář a cíl soubor, za nimi následuje seznam balíčků, které se mají převést (ano, do jednoho souboru je možné uložit více balíčků).
Přesně tak, hotovo. Nyní už stačí jenom baliček nainstalovat:
# pkgadd -d /var/spool/pkg ABCLhello Processing package instance <abclhello> from The world famous hello world program.(sparc) 1.0 Using </opt> as the package base directory. ## Processing package information. ## Processing system information. ## Verifying disk space requirements. ## Checking for conflicts with packages already installed. ## Checking for setuid/setgid programs. Installing The world famous hello world program. as <ABCLhello> ## Installing part 1 of 1. /opt/hello/bin/hello /opt/hello/share/man/man1/hello.1 [ verifying class <none> ] Installation of <ABCLhello> was successful. # /opt/hello/bin/hello Hello, world! </none></abclhello>
Představme si, že dál pracujeme na našem mistrovském díle a po mnoha měsících usilovné práce do našeho programu přidáme možnost konfigurace kdovíčeho pomocí souboru /opt/hello/etc/hello.conf
. Upravíme tedy číslo verze v pkginfo
a přidáme do souboru prototype
dva řádky:
d none hello/etc 0755 jdoe other f none hello/etc/hello.conf 0555 jdoe other
Potom znovu vytvoříme balíček a rozešleme ho šťastným zákazníkům, kteří pomocí pkgrm
odstraní starou verzi a pak nainstalují novou. Všechno funguje a svět je krásný. Pak ale zákazníci začnou být nešťastní, protože najdou v našem programu chybu. Chybu opravíme, a protože ještě neumíme patchovat (o tom bude další článek), vyrobíme další, třetí verzi balíčku, rozešleme ji zákazníkům a čekáme na jejich chválu. Té se ale nedočkáme, zákazníci jsou totiž pořád nešťastní. Proč? Inu, strávili spoustu času konfigurováním našeho programu, a když odinstalovali jeho druhou verzi aby mohli nainstalovat třetí, jejich pracně vytvořený konfigurační soubor zmizel. A kdo dneska zálohuje, že?
A to je chvíle, kdy nastupují výše zmíněné typy a třídy. Správně totiž nové položky v prototype
měly vypadat takhle:
d none hello/etc 0755 jdoe other e renameold hello/etc/hello.conf 0755 jdoe other i i.renameold i r.renameold
V řádku pro hello.conf
jsme uvedli typ "e" a
třídu "renameold". Typ "e" nebo "editable" znamená, že příslušný soubor může být modifikován uživatelem, sdílen s jinými programy, prostě že je potřeba k němu přistupovat opatrně. Co přesně ten "opatrný přístup" znamená, určíme pomocí konkretní třídy, kterou vytvoříme.
Název třídy můžeme zvolit libovolně, pokud možno výstižně. Pro každou třídu musíme vytvořit class action scripty, neboli skripty, které se postarají o správné doručení souboru na cílový počítač, případně o správné odstranění provedených změn při odinstalaci balíčku. Tyto skripty musejí být uvedeny v prototypu s typem "i" a jejich jména musí být i.jménotřídy
pro instalační skript, respektive r.jménotřídy
pro odinstalační skript.
Jak by mohly vypadat skripty pro naši třídu renameold
?
$ cat i.renameold #!/bin/sh # Ano, /bin/sh, coz na Solarisu znamena stary dobry hloupy Bourne Shell, # nikoliv BASH, jak jste mozna zvykli z Linuxu. # # Na vstupu skript obdrzi pro kazdy soubor jeden radek. # Na kazdem radku je nejprve cesta k docasne kopii instalovaneho souboru, # potom cesta kam se tento soubor ma nainstalovat. while read src dst do # Existuje uz cilovy soubor? if [ ! -f ${dst} ] ; then # Ne, tak to tam proste prekopirujeme. cp ${src} ${dst} else # Hm, existuje. Je stejny jako to co chceme instalovat? # Pokud ano, nemusime delat nic. cmp -s ${src} ${dst} if [ $? != 0 ] ; then # Neni stejny. Zazalohujeme jeho starou verzi. cp ${dst} ${dst}.old # Zkopirujeme novou verzi na spravne misto. cp ${src} $dst} # A dame o tom userovi vedet. echo "Existing file was renamed: ${dst} ${dst}.old" fi fi done exit 0 $ cat r.renameold #!/bin/sh # # Nedelame nic, proste nechame soubor jak je. exit 0
Mimochodem, asi tušíte, co znamenala všechna ta none
, která píšeme do pole pro název třídy u "obyčejných" souborů. To je základní třída, která prostě při instalaci soubor zkopíruje na jeho místo a při odinstalaci jej zase odstraní. Pro ni žádné class action skripty dodávat nemusíte, Solaris ji zvládne sám.
A hotovo. Pokud nainstalujeme tento balíček a pak jej odstraníme, konfigurační soubor zůstane na svém místě protože skript r.renameold
nic nedělá. Když potom baliček nainstalujeme znovu, ať už stejnou nebo novější verzi, i.renameold
se postará o to, aby stará verze byla zazálohována a až potom se nainstalovala nová.
Samozřejmě, že toto řešení není ideální, protože udržujeme jenom jednu záložní kopii souboru a uživatel musí ručně přenést své změny do nové verze. Je ale asi jasné, že trochu chytřejší instalační skript by se mohl pokusit přenést změny ze staré verze souboru do nové (a až když by to nezvládl, tak by provedl to co teď), v případě potřeby zkonvertovat konfigurační soubor ze starého do nového formátu a podobně. Možností je nespočetně. Každý speciální soubor má vlastní požadavky, které lze snadno řešit speciální třídou a příslušnými class action skripty.
Kromě jednotlivých doručovaných souborů s sebou balíček může nést i několik skriptů, které se spouštějí v různých okamžicích jeho instalace a odinstalace. Jejich použití shrnuje následující tabulka:
Skript | Účel | Smí modifikovat systém? | Smí komunikovat s uživatelem? | Smí ukončit instalaci? | |
---|---|---|---|---|---|
request | Získat dodatečné informace od uživatele. | Ne | Ano | Ne | |
checkinstall | Ověřit možné další podmínky pro instalaci balíčku. Poslední šance přerušit instalaci. | Ne | Ne | Ano | |
preinstall | Operace které je potřeba provést před instalací (např. pozastavení démonů). | Ano | Ne | Ne | |
postinstall | Operace které je potřeba provést po instalaci (např. znovuspuštění démonů). | Ano | Ne | Ne | |
preremove | Operace, které je potřeba provést před odinstalováním. | Ano | Ne | Ne | |
postremove | Operace, které je potřeba provést po odinstalování. | Ano | Ne | Ne |
Stejně jako class action skripty, i tyto skripty musejí být uvedeny v prototypu s typem "i". Takže kdybychom chtěli v našem balíčku po instalaci restartovat příslušného démona, přidáme postinstall
skript. prototype
pak bude vypadat takhle:
d none hello 0755 jdoe other d none hello/bin 0755 jdoe other f none hello/bin/hello 0555 jdoe other d none hello/share 0755 jdoe other d none hello/share/man 0755 jdoe other d none hello/share/man/man1 0755 jdoe other f none hello/share/man/man1/hello.1 0644 jdoe other d none hello/etc 0755 jdoe other e renameold hello/etc/hello.conf 0755 jdoe other i i.renameold i r.renameold i postinstall i pkginfo
Skript sám pak bude velmi jednoduchý:
$ cat postinstall #! /bin/sh # Pouzivate prece SMF, ne? svcadm restart hellod
Jak už jsem napsal úvodem, tento článek byl jenom velmi stručným úvodem do balíčkovacího systému Solarisu, podrobnější informace najdete ve výborné dokumentaci a manuálových stránkách, které popisují nejen příkazy jako pkgmk(1) nebo pkgproto(1), ale i formáty souborů jako prototype(4) nebo pkginfo(4). Doufám ale, že se mi podařilo ukázat, jak jednoduchý a současně mocný systém to je a že jsem ve vás probudil aspoň jiskřičku zájmu. Pokud ano, můžete se těšit na další článek, tentokrát o patchování.
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.