Zvyklosti vývoje Dynamicky linkované objekty Závěr Základy vývoje v prostředí GNU/Linux Tématicky zaměřený vývoj aplikací v jazyce C skupina Systémové programování – Linux Jiří Novosad Fakulta informatiky Masarykova univerzita novosad@fi.muni.cz 21. září 2014 J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 1 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Zvyklosti vývoje v prostředí GNU/Linux zvyklosti v chování aplikací, interakce aplikací s okolím J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 2 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Adresářová struktura GNU/Linux Filesystem Hierarchy Standard www.pathname.com/fhs/pub/fhs-2.3.html /bin/ obecné systémové binárky pro všechny uživatele /boot/ soubory potřebné pro zavaděč, jádro /dev/ soubory zařízení (disky, usb, porty, . . . ) /etc/ konfigurační soubory /lib/ sdílené systémové knihovny modules/ moduly jádra /proc/ speciální virtuální filesystém obsahující informace o jádře /sbin/ obecné systémové binárky pro privilegované uživatele /tmp/ dočasné soubory /usr/ soubory potřebné pro běžnou práci bin/ binárky programů doc/ dokumentace aplikací include/ hlavičkové soubory lib/ další sdílené knihovny local/ aplikace, knihovny, . . . instalované ze zdrojových souborů man/ manuálové stránky sbin/ další systémové binárky share/ konfigurační soubory a další nastavení aplikací /var/ pracovní (měnící se) soubory pro běžící programy a služby J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 3 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Parametry příkazové řádky Základní způsob předávání vstupních informací programu. Pravidla popsána v rámci normy POSIX → GNU Standards. Používejte standardní názvy parametrů a standardní chování. Obvyklá syntax přepínačů: - - -- -- -- --= Využívejte standardní funkce: getopt – zpracovává krátké parametry getopt_long – zpracovává dlouhé parametry, není součástí POSIX (GNU rozšíření) J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 4 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Proměnné prostředí Slouží k nastavení chování aplikace. Z příkazové řádky: export MYVAR=ahoj echo $MYVAR Z aplikace: getenv() – vrátí hodnotu proměnné putenv(), setenv() – nastaví hodnotu proměnné J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 5 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Proměnné prostředí Slouží k nastavení chování aplikace. Z příkazové řádky: export MYVAR=ahoj echo $MYVAR Z aplikace: getenv() – vrátí hodnotu proměnné putenv(), setenv() – nastaví hodnotu proměnné Užitečné proměnné prostředí $HOME $USER $PATH $LD_LIBRARY_PATH J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 5 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Proměnné prostředí – bezpečnost Nespoléhejte se na proměnné prostředí (PATH, IFS, HOME, . . . ) – považujte je za nedůvěryhodný vstup. extern char** environ; Dezinfekce sady proměnných prostředí převzetí vybraných původních hodnot smazání prostředí (clearenv(3)/unsetenv(3)) nastavení proměnných prostředí na bezpečné hodnoty J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 6 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr úkol Napište si vlastní verzi aplikace printenv(1) Za domácí úkol včetně všech parametrů J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 7 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Konfigurační soubory Obvyklé umístění v /etc/, ale také /usr/share/. Neexistuje jednotný formát konfiguračních souborů. proměnná hodnota (sshd) XML (D-Bus) vlastní syntax (Apache) J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 8 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Konfigurační soubory Obvyklé umístění v /etc/, ale také /usr/share/. Neexistuje jednotný formát konfiguračních souborů. proměnná hodnota (sshd) XML (D-Bus) vlastní syntax (Apache) → Snažte se dodržovat obvyklé konvence pro typ aplikace, kterou vytváříte. J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 8 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Opravy kódu Standardní utility diff a patch J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 9 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Opravy kódu Standardní utility diff a patch Postup vytvoření a aplikace patche vytvořte kopii originálu (celou adresářovou strukturu, konkrétní soubor) upravte kód diff -ur file.orig file > file.patch patch -p0 -i file.patch J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 9 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr úkol Ve studijních materiálech je soubor param.c Najděte v kódu chybu a připravte patch. J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 10 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Dynamicky linkované objekty dynamické knihovny, kód přidávaný za běhu (pluginy) J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 11 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (I) API – Application Programming Interface (vysokoúrovňové) rozhraní mezi zdrojovým kódem a knihovnami – zdrojový kód lze zkompilovat ABI – Application Binary Interface (nízkoúrovňový) popis toho, jak jsou data uložena v paměti, tento popis používá compiler např. při referenci proměnných, umožňuje již zkompilovanému kódu běžet v prostředí s kompatibilním ABI API i ABI měňte co nejméně často (raději funkce přidávejte). Rozhodně rozumně verzujte při změnách! Změny v ABI jsou nebezpečnější – nemusí být hned vidět a přijdete na ně až když něco nefunguje. J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 12 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – API kompatibilní, ABI nekompatibilní změna pořadí položek struktury – J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – API kompatibilní, ABI nekompatibilní změna pořadí položek struktury – API kompatibilní, ABI nekompatibilní odstranění funkce – J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – API kompatibilní, ABI nekompatibilní změna pořadí položek struktury – API kompatibilní, ABI nekompatibilní odstranění funkce – API nekompatibilní přidání nové funkce – J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – API kompatibilní, ABI nekompatibilní změna pořadí položek struktury – API kompatibilní, ABI nekompatibilní odstranění funkce – API nekompatibilní přidání nové funkce – API zpětně kompatibilní J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr API vs. ABI (II) Příklady reimplementace funkce – API, ABI kompatibilní změna hodnoty položky enumu – API kompatibilní, ABI nekompatibilní změna pořadí položek struktury – API kompatibilní, ABI nekompatibilní odstranění funkce – API nekompatibilní přidání nové funkce – API zpětně kompatibilní nekompatibilní API – aplikaci je třeba upravit nekompatibilní ABI – aplikaci je třeba pouze překompilovat J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 13 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Dynamické (sdílené) knihovny kolekce kódů dynamicky připojitelných k aplikaci za běhu připojitelných i k několika aplikacím najednou způsob jak předcházet duplikaci kódu šetří diskové místo snadná aktualizace a oprava chyb program je pak ale závislý na požadovaných knihovnách J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 14 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Dynamické knihovny v Linuxu I ldconfig(8) vytvoří symbolické odkazy na instalované knihovny – linker většinou použije právě tyto symlinky vytvoří cache instalovaných knihoven pro dynamický linker potřebné soubory včetně informace o umístění knihoven jsou v /etc/ld.so.* obvyklé umístění knihoven je /lib/,/lib64/,/usr/lib/,/usr/lib64/, . . . proměnné prostředí LD_LIBRARY_PATH – umistění knihoven (před standardními cestami) LD_PRELOAD – knihovna, která má být přilinkována jako první LD_DEBUG – LD_DEBUG=help date; LD_DEBUG=libs date J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 15 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Dynamické knihovny v Linuxu II soname: ’lib’ + jméno + ’.so.’ + verze (libpam.so.0) /lib/ld-linux.so.X – run-time linker (loader) ldd(1) – zjistí závislosti dynamických objektů objdump(1), nm(1), readelf(1) – vypíše informace o objektových souborech Vytváření dynamické knihovny vytvořte objekty s kódem nezávislým na pozici (PIC) gcc -fPIC -c file.c z objektů vytvořte dynamickou knihovnu gcc -shared -Wl,-soname,libmyname.so.1 \ -o libmyname.so.1.0.0 file.o J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 16 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr úkol napište vlastní verzi funkce localtime() - je na vás, jaký čas bude vracet vyzkoušejte si LD_PRELOAD s vaší verzí localtime() na programu date J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 17 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Pluginy (dynamicky linkovaný kód) Otevření dynamického objektu za běhu aplikace. dlopen() dlsym() dlerror() dlclose() Při překladu (gcc) je nutné použít přepínač -ldl. Ukazatel na funkci: návratový_typ (*identifikátor)(seznam_typů_parametrů); J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 18 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Pluginy (dynamicky linkovaný kód) Otevření dynamického objektu za běhu aplikace. dlopen() dlsym() dlerror() dlclose() Při překladu (gcc) je nutné použít přepínač -ldl. Ukazatel na funkci: návratový_typ (*identifikátor)(seznam_typů_parametrů); void* (*funkce)(void* ukazatel, size_t velikost); J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 18 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Pluginy (dynamicky linkovaný kód) Otevření dynamického objektu za běhu aplikace. dlopen() dlsym() dlerror() dlclose() Při překladu (gcc) je nutné použít přepínač -ldl. Ukazatel na funkci: návratový_typ (*identifikátor)(seznam_typů_parametrů); void* (*funkce)(void* ukazatel, size_t velikost); http://tldp.org/HOWTO/Program-Library-HOWTO/dl-libraries.html J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 18 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Závěr domácí úkoly a zdroje J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 19 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Domácí úkol (rozšíření úkolu z hodiny) Využijte princip pluginu a napište 2 knihovny, které různě implementují podobnou funkcionalitu (např. tisknou různé zprávy) Vytvořte program, který volá jednotlivé funkce podle přání uživatele – při startu programu podle parametru příkazové řádky nebo proměnné prostředí (priorita je na vás). Program musí uživateli poskytnout možnost vypsat zprávu (použít funkce) opakovaně (včetně změny použité funkce) – způsob interakce s uživatelem je na vás. Nezapomeňte na srozumitelnou nápovědu a ošetření chyb! Vše uložte do SVN. J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 20 / 21 Zvyklosti vývoje Dynamicky linkované objekty Závěr Zdroje parametry příkazové řádky pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html www.gnu.org/prep/standards/standards.html#Command_002dLine-Interfaces www.gnu.org/prep/standards/standards.html#Option-Table proměnné prostředí etutorials.org/Programming/secure+programming/Chapter+1.+Safe+ Initialization/1.1+Sanitizing+the+Environment/ www.securecoding.cert.org/confluence/display/seccode/ENV03-C.+Sanitize+ the+environment+when+invoking+external+programs dynamicky linkované objekty tldp.org/HOWTO/Program-Library-HOWTO/index.html ostatní www.di.uniovi.es/∼cernuda/noprog_ENG.html wezfurlong.org/blog/2006/dec/coding-for-coders-api-and-abi-considerations-in-an- evolving-code-base J. Novosad 2 – Základy vývoje v prostředí GNU/Linux 21. září 2014 21 / 21