Patchset készítés

A HupWiki-ből...

A HOGYAN célja a patchset készítés közben előforduló leggyakoribb lépések és problémák ismertetés, egy konkrét példán keresztül (az általam valaha karbantartott -pear Linux patchsetből annyi, ami elég az oktatáshoz). Igazság szerint nem annyira bonyolult a dolog, ha egyszer belejön az ember, de nem találtam olyan leírást, ami felöleli az egész témát. (Ez csak egy HOGYAN, ezért nem kell naprakésznek lennie a felhasznált komponensek verzióját illetően, természetesen, ha megjelent újabb, akkor azt használd.)

Megpróbáltam a HOGYANt a lehető legközérthetőbbre megírni, de mivel eléggé száraz téma, ezért vagy túl sokat magyaráz az ember (és esetleg túlbonyolítja) vagy túl keveset (és gondolkozásra késztet). Ezért megpróbálom az arany középutat, tehát kezdetben elmagyarázni egy adott probléma megoldását, később már csak utalni erre. (Ez nem vonatkozik a másolás és kitömörítés rejtélyére. Ezek ismerete úgyis "létkérdés".)

Tartalomjegyzék

Erőgyűjtés

Egyébként mi az a patchset?

Egy "patch" arra szolgál, hogy segítségével megváltoztathasd adott állományok tartalmát. A patchset nem más, mint több patch (a könnyebb kezelhetőség érdekében) úgy összegyúrva, hogy ne zavarjanak be egymásnak.

Miért készítsek patchsetet?

Amennyiben szeretnél új dolgokat tanulni és egy "saját" speckózott kernelt használni, akkor érdemes nekiugrani. (Nem beszélve a rajongó lánykáktól várható képekről. Elvégre erről szól az OSS/FS, nem? ;-)

Milyen előkövetelmények vannak?

Nem árt ismerni az alapvető shell parancsokat és letudni pár sikeres vanilla kernel fordítást. A legtöbb probléma megfelelő szintű "logika" képességgel megoldható (alapvető C sem árt).

Mit fog tartalmazni a patchset?

  • 2.6 Kernel -stable ága
  • -ck patchset
  • nmap_freak és stealth_patch

Mire lesz szükségem?

  • patch kezelési programok: patch, quilt
  • diff program: diff, tkdiff, ...
  • editor: vim, emacs, ...
  • böngésző

Milyen egy patch felépítése?

Példának álljon a leendő 2.6.15-pear1.diff:

--- linux-2.6.15/Makefile       2006-02-18 20:20:01.000000000 +0100
+++ linux-2.6.15/Makefile-pear1 2006-02-18 20:24:39.000000000 +0100
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 15
-EXTRAVERSION = .4
+EXTRAVERSION = -pear1
 NAME=Sliding Snow Leopard

 # *DOCUMENTATION*
(...)

Magyarázat:

  • az első sor jelenti, hogy a patch elkészítésekor mi volt az eredeti állomány, ami ellen készült a második sorban lévő állomány (tehát a patchelendő állomány nevét az első sorból veszi); az időpontok tájékoztatási jellegűek
  • a harmadik sor jelzi, hogy a patch állományban ezen részlete a patchelendő állomány 7. soráig érvényes, ameddig egy sort fog eltávolítani és egy sort fog hozzáadni (emiatt a patchelés után is a 7. sorig érvényes a változás); az utolsó sor csak tájékoztatási jellegű, a patch progi ettől függetlenül is képes megtalálni a helyes részt, ha megváltoztatandó rész előtti és mögötti 3 sor nem változott
  • egyébként a "@@" után szerepelhet a megváltoztatandó rész előtt utoljára szereplő függvény neve (ez se követelmény)
  • tehát, amelyik sor előtt "-" van, az a sor el lesz távolítva, a "+" kezdetű sorok hozzá lesznek adva, a nem változó sorok előtt szóköz van (fontos!)
  • természetesen egy patch állományban több változás is lehet
  • összességében a patch működése elég rugalmas, a lényeg a patchelendő állomány pathje (lásd "-p" kapcsoló) és neve, a patchelés előtti és utáni sorhoz és az eltávolítandó (és 3-3 ellenőrző) sor pontos tartalma (whitespace!)

Előkészületek

A leendő összetevők könnyebb kezelése érdekében érdemes pld. egy download/ könyvtárat létrehozni, és mindig ide tölteni az összetevőket.

Először letöltjük a legutolsó 2.6 kernelt (a főverziót, nem a -stablet, hogy izgalmasabb legyen), a www.kernel.org/pub/linux/kernel/v2.6/ oldalról (az írás pillanatában az aktuális változat: linux-2.6.15.tar.bz2).

Megérkezés után tömörítsd ki az /usr/src-be és lépj be a létrejött új könyvtárba.

A fejezet zárásaként felkészítjük a forrást a patchelésre. Nagymennyiségű patch könnyed kezelését teszi lehetővé a quilt, ennek két követelményét fogjuk teljesíteni:

  • létrehozzuk a patches/ könyvtárat, ide fognak a patch állományok kerülni
  • a quilt a series állomány alapján kezeli a patcheket, ezt létrehozzuk valami szép fejléccel:
#-pear patchset
#2.6.15-pear1 - 20060221

(Itt érdemes megjegyezni, hogy a "series" állomány is támogatja a soreleji #-et, mint megjegyzést. Így lehet kikapcsolni ideigelenesen a nem kívánt patcheket.)

Egyszerű patch beillesztése

Először a legfrissebb -stablet olvasztjuk rá a kernelre, ehhez letöltjük a The Linux Kernel Archives oldalon a "The latest stable version of the Linux kernel is:" melletti link segítségével (az íráskori aktuális változat: 2.6.15.4).

(Megj.: természetesen az adott subversionhoz tartozó magasabb sorszámú -stable kiadások tartalmazzák az előző javításokat is.)

Letöltés után kitömörítjük a patch-2.6.15.4.bz2 állományt a patches/ alkönyvtárba.

A quilt használatba vétele előtt kipróbáljuk, hogy felmegy-e a patch:

  1. visszalépünk a kernel forrás könyvtárába
  2. kipróbáljuk a patchet: patch -i patches/patch-2.6.15.4 --dry-run -p1
    • a kapcsolók magyarázata: "-i" egy állományból vegye a patchet, "--dry-run" ne végezzen tényleges írást, "-p1" prefix javítás, mivel a patch a "patches/" könyvtárban van

Ha minden oké:

/usr/src/linux-2.6.15# patch -i patches/patch-2.6.15.4 --dry-run -p1
patching file Makefile
patching file arch/i386/kernel/acpi/boot.c
patching file arch/ppc/boot/simple/Makefile
(...)
patching file sound/usb/usbaudio.c
/usr/src/linux-2.6.15#

Ha -p1 nélkül nyomnánk:

/usr/src/linux-2.6.15# patch -i patches/patch-2.6.15.4 --dry-run
patching file Makefile
can't find file to patch at input line 18
Perhaps you should have used the -p or --strip option?
The text leading up to this was:
--------------------------
|diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
|index 447fa9e..85ca409 100644
|--- a/arch/i386/kernel/acpi/boot.c
|+++ b/arch/i386/kernel/acpi/boot.c
--------------------------
File to patch: (üss ctrl+c -t)
/usr/src/linux-2.6.15#

Mint látható eleve az "a/" könyvtáron belül keresné az adott állományt, ezt bíráltuk felül a "-p1" segítségével (ne vegye figyelembe az első "/" előtti részt).

(Megj.: a patch -R (...) visszavonja az adott patchet.)

Oké, felmegy a patch, illesszük be a seriesbe a rá vonatkozó részt:

(...) 3.sor
#-stable
patch-2.6.15.4

Most már kipróbálhatjuk quilttal, a quilt push utasítás hatására a seriesben sorra kerülő patchet próbálja beilleszteni.

/usr/src/linux-2.6.15# quilt push
Applying patch patch-2.6.15.4
patching file Makefile
patching file arch/i386/kernel/acpi/boot.c
patching file arch/ppc/boot/simple/Makefile
(...)
patching file sound/pci/emu10k1/emumixer.c
patching file sound/usb/usbaudio.c
 
Now at patch patch-2.6.15.4
/usr/src/linux-2.6.15#

(Egyébként a "quilt" kezeli a .gz/.bz2 tömörített patcheket is, de most oktató módban ezzel nem bonyolítjuk a dolgot.)

Tehát a "patch-2.6.15.4"-et sikeresen hozzáadta, ezt le is ellenőrizhetjük a quilt applied paranccsal, ami kilistázza a jelenleg beadagolt patcheket. Ez főleg akkor hasznos, ha sok patchet rakosgatunk ki-be és szeretnénk tudni, hogy mi van épp fenn.

Léphetünk tovább.

Többgyermekes patch

Hozzáadjuk a -ck patcheket:

Kitömörítést a kernel forrás könyvtárában:

/usr/src/linux-2.6.15# tar xvfj path/patches.tar.bz2 
patches/
patches/mm-swap_prefetch-19.patch
patches/series-2.6.15-ck4
(...)
patches/schedbatch-2.11.diff
patches/series
patches/schedrange-1.diff
/usr/src/linux-2.6.15#

Mint látható a -ck broken-out sok patchből áll (innen a neve), de ebből nem kell az összes. Ezért találták ki a "series" állományt, mert a quilt csak az ebben szereplő patchekkel foglalkozik, nem az összes "patches/" könyvtárban lévővel.

Most megnyitjuk a -ck "series" állományát ("patches/series-2.6.15-ck4") és átmásoljuk a tartalmát a sajátunkba. Kivéve a "patch-2.6.15.4.bz2"-t (ezt már beolvasztottuk) és a "2615ck4-version.patch"-t (a végén készítünk sajátot).

Tehát a saját seriesünk:

(...) 6.sor
#-ck4
sched-staircase13.2.patch
sched-staircase13.2_13.3.patch
(...) 28.sor
dynticks-i386_only_config.patch
sched-staircase13.3_13.4.patch

Ezután "quilt push -a", tehát minden seriesben lévő patchet egyesével beolvasztunk:

/usr/src/linux-2.6.15# quilt push -a
Applying patch sched-staircase13.2.patch
patching file fs/proc/array.c
patching file include/linux/sched.h
(...)
Applying patch sched-staircase13.3_13.4.patch
patching file kernel/sched.c
 
Now at patch sched-staircase13.3_13.4.patch
/usr/src/linux-2.6.15#

Felraktunk már egy rakat patchet, ideje tovább ismerkedni a "quilt"tel: a quilt pop visszafejt egy patchett a seriesből.

Tehát egy "quilt pop -a" most visszaszed mindent a vanilla állapotba:

/usr/src/linux-2.6.15# quilt pop -a
Removing patch sched-staircase13.3_13.4.patch
Restoring kernel/sched.c

Removing patch dynticks-i386_only_config.patch
(...)
Restoring sound/usb/usbaudio.c

No patches applied
/usr/src/linux-2.6.15#

Miután ezzel is megismerkedtünk, rakjuk fel újra az összes patchet (ugyebár: quilt push -a).

Hunk! FAILED!

Eddig egyszerű dolgunk volt, mivel minden patch simán felment, de ideje megismerkedni a patchset készítő két "barátjával" a Hunk és a FAILED üzenettel. Ehhez a stealt_patch és nmap_freak nevü kernel patcheket fogjuk használni, amik az "os detection"t és az "nmap scannelés"t akadályozzák meg több-kevesebb sikerrel (igazság szerint egyik sem egy production safe megoldás, ezért ha nem akarsz vacakolni, akkor be se kapcsold őket kernel konfigurálás közben; de oktatási célra pont jók lesznek). Mindkét patch eredeti kiadása már rég elavult (http://packetstormsecurity.nl/UNIX/patches/), ezért az eredetieknél frissebb verziókat fogjuk használni a Wolkból.

Tehát az "nmap_freak":

Ez már munkásabb lesz, először másold be a "patches/" könyvtárba mondjuk nmap-freak.patch néven.

Eztán kipróbáljuk "patch"el:

/usr/src/linux-2.6.15# patch -i patches/nmap-freak.patch --dry-run -p1

patching file include/linux/sysctl.h
Hunk #1 FAILED at 337.
1 out of 1 hunk FAILED -- saving rejects to file include/linux/sysctl.h.rej
patching file net/ipv4/Kconfig
Hunk #1 succeeded at 367 with fuzz 2 (offset 2 lines).
patching file net/ipv4/icmp.c
Hunk #1 succeeded at 190 with fuzz 2.
Hunk #2 succeeded at 790 (offset 4 lines).
patching file net/ipv4/sysctl_net_ipv4.c
Hunk #1 FAILED at 37.
Hunk #2 succeeded at 336 (offset -18 lines).
1 out of 2 hunks FAILED -- saving rejects to file net/ipv4/sysctl_net_ipv4.c.rej
patching file net/ipv4/tcp_ipv4.c
Hunk #1 succeeded at 80 with fuzz 2 (offset -5 lines).
Hunk #2 succeeded at 683 (offset -500 lines).
/usr/src/linux-2.6.15#

Mi a gáz?

  • Hunk #1 FAILED at 337.: a .patch elkészültekor az adott állomány kicserélendő része egy, a mostanitól különböző állapotban volt, ezért a patch program úgy ítéli meg, hogy nem lehet megfelelően beolvasztani a patchet; ezt mindjárt kezelésbe vesszük
  • Hunk #1 succeeded at 367 with fuzz 2 (offset 2 lines).: a .patch által igényelt állományrész és a jelenlegi állományrész szintén nem egyezik, de a patch program rájött, hová kéne rakni (ez általában nem jelent tényleges problémát, ezért most csak a "FAILED"ekkel foglalkozunk)

Tehát a "FAILED" problémák kibogozása következik.

Fogjunk két editort és nézzük meg, mi van az "include/linux/sysctl.h" állományban és az "nmap_freak.patch" erre vonatkozó részében:

nmap_freak:

(...) 4.sor
diff -Naurp linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h linux-2.6.3-wolk1.0-work/include/linux/sysctl.h
--- linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h       2004-02-27 15:24:55.000000000 +0100
+++ linux-2.6.3-wolk1.0-work/include/linux/sysctl.h     2004-02-27 15:35:10.000000000 +0100
@@ -337,6 +337,8 @@ enum
 	NET_TCP_STACK_SYNFIN=98,
 	NET_TCP_STACK_BOGUS=99,
 	NET_TCP_STACK_ACK=100,
+	NET_IPV4_ICMP_RESTRICT=101,
+	NET_IPV4_TCP_RESTRICT=102,
 };

 enum {
(...)

Az "include/linux/sysctl.h" a 337. sortól (ami a FAILED üzenetnél jelzett):

	(...) 336.sor
	NET_IPV4_TCP_RETRIES2=48,
	NET_IPV4_TCP_FIN_TIMEOUT=49,
	NET_IPV4_IP_MASQ_DEBUG=50,
        (...)

Oké, egyértelműen látszik, hogy a jelenlegi nmap_freak.patch-ünk készítése óta fejlesztettek egy keveset a kernelen; szerencsére ez csak egy header, ezért túl sok kárt nem okozhatunk benne: egyszerűen úgy módosítjuk az "nmap_freak.patch"-et, hogy a "sysctl.h" megfelelő függvényének végére (jelenleg ez a 393. sor) kényelmesen beillesztődhessen (és az értékeit is újraszámozzuk).

A "sysctl.h" azon része, ahová a patch kerülni fog:

(...) 389. sor
	NET_TCP_BIC_BETA=108,
	NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109,
	NET_TCP_CONG_CONTROL=110,
	NET_TCP_ABC=111,
};

enum {
	NET_IPV4_ROUTE_FLUSH=1,
(...)

Íme a módosított nmap_freak részlet:

(...) 4. sor
diff -Naurp linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h linux-2.6.3-wolk1.0-work/include/linux/sysctl.h
--- linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h       2004-02-27 15:24:55.000000000 +0100
+++ linux-2.6.3-wolk1.0-work/include/linux/sysctl.h     2004-02-27 15:35:10.000000000 +0100
@@ -395,6 +395,8 @@ enum
 	NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109,
 	NET_TCP_CONG_CONTROL=110,
 	NET_TCP_ABC=111,
+	NET_IPV4_ICMP_RESTRICT=112,
+	NET_IPV4_TCP_RESTRICT=113,
 };
 
 enum {
(...)

Hol szívhatjuk meg?

  • figyeljünk arra, hogy mikor tab és mikor space a whitespace
  • a változást nem tartalmazó sorok (tehát ami nem "+" vagy "-" kezdetű) előtt egy szóköznek kell lennie

Mentés, és próbáljuk ki megint:

# patch -i patches/nmap-freak.patch --dry-run -p1
patching file include/linux/sysctl.h
patching file net/ipv4/Kconfig
(...)

Cool, az első FAILED kijavítva.

Most jöhet a "net/ipv4/sysctl_net_ipv4.c" 37. sorát érintő probléma vizsgálata: keresd ki a patchben és az eredeti állományban, majd csodálkozhatsz, mert ezt is alaposan átírták azóta; de mi nem fogunk drasztikus változásokat eszközölni. Az "#ifdef CONFIG_SYSCTL" elé kell kerülni a mi függvény definícióiknak (ez egy régebbi kernel forrás sysctl_net_ipv4.c forrásának és az nmap_patch problémás részének összevetésével kiderül).

Az nmap_freak megváltozó része:

(...) 69. sor
diff -Naurp linux-2.6.3-wolk1.0-fullkernel/net/ipv4/sysctl_net_ipv4.c linux-2.6.3-wolk1.0-work/net/ipv4/sysctl_net_ipv4.c
--- linux-2.6.3-wolk1.0-fullkernel/net/ipv4/sysctl_net_ipv4.c   2004-02-27 15:33:07.000000000 +0100
+++ linux-2.6.3-wolk1.0-work/net/ipv4/sysctl_net_ipv4.c 2004-02-27 15:34:13.000000000 +0100
@@ -37,6 +37,11 @@ extern int sysctl_ip_dynaddr;
 /* From af_inet.c */
 extern int sysctl_ip_nonlocal_bind;
 
+#ifdef CONFIG_IP_NMAP_FREAK
+extern int sysctl_icmp_restrict;
+extern int sysctl_tcp_restrict;
+#endif
+
 #ifdef CONFIG_SYSCTL
 static int tcp_retr1_max = 255;
 static int ip_local_port_range_min[] = { 1, 1 };
(...)

Oké, mindkét FAILED kijavítva, nyomunk még egy "patch --dry-run (...)" parancsot és ha tényleg minden rendben (mármint a "Hunk"okkal most nem foglalkozunk), akkor az nmap_freak bekerülhet a seriesbe:

(...) 29. sor
sched-staircase13.3_13.4.patch

#other
nmap-freak.patch

Nyomassuk fel a "quilt"tal.

(Természetesen senki sem szeret fölöslegesen dolgozni, ezért a most módosított patchet nyugodtan használhatjuk egy újabb kernel verzióhoz is.)

Inkrementális patch

Az eddigiek után inkább csak érdekesség.

Mivel az nmap_freak beolvasztása során jelentősen megváltozott az "include/linux/sysctl.h", ezért a "stealt_patch" inkrementális lesz, magyarul olyan változtatást tartalmaz, ami miatt csak az "map_freak" után lehet beilleszteni a kernel forrásba.

Másoljuk át a "patches/"-be IPv4-stealth.patch néven.

Jöhet a szokásos kompatibilitási próba:

/usr/src/linux-2.6.15# patch -i patches/IPv4-stealth.patch --dry-run -p1
patching file include/linux/sysctl.h
Hunk #1 FAILED at 334.
1 out of 1 hunk FAILED -- saving rejects to file include/linux/sysctl.h.rej
patching file net/ipv4/Kconfig
Hunk #1 succeeded at 367 with fuzz 2 (offset 24 lines).
patching file net/ipv4/sysctl_net_ipv4.c
Hunk #1 succeeded at 29 with fuzz 2 (offset -18 lines).
Hunk #2 succeeded at 336 (offset 13 lines).
patching file net/ipv4/tcp_input.c
Hunk #1 succeeded at 75 with fuzz 1.
patching file net/ipv4/tcp_ipv4.c
Hunk #1 succeeded at 80 (offset 1 line).
Hunk #2 succeeded at 1222 with fuzz 1 (offset -547 lines).
Hunk #3 succeeded at 1280 (offset -547 lines).
/usr/src/linux-2.6.15#

Itt szerencsére csak egy "FAILED" lesz és ő is a "sysctl.h"-ban, ezt már letárgyaltuk, ezért csak a javított "IPv4-stealth.patch" részlet:

(...) 4.sor
diff -Naurp linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h linux-2.6.3-wolk1.0-work/include/linux/sysctl.h
--- linux-2.6.3-wolk1.0-fullkernel/include/linux/sysctl.h       2004-02-27 11:52:32.000000000 +0100
+++ linux-2.6.3-wolk1.0-work/include/linux/sysctl.h     2004-02-27 14:44:49.000000000 +0100
@@ -334,6 +334,10 @@ enum
 	NET_TCP_ABC=111,
 	NET_IPV4_ICMP_RESTRICT=112,
 	NET_IPV4_TCP_RESTRICT=113,
+	NET_IPV4_IP_MASQ_UDP_DLOOSE=114,
+	NET_TCP_STACK_SYNFIN=115,
+	NET_TCP_STACK_BOGUS=116,
+	NET_TCP_STACK_ACK=117,
 };
 
 enum {
(...)

(Ha rendesen akarod csinálni, akkor nevezd át mondjuk IPv4-stealth-fixed.patch-ra, így egyértelműbb lesz, hogy lényeges változás van benne.)

A többi ismerős, újabb "patch --dry-run" próba, majd "series" átírás és "quilt push".

Saját patch készítés

Az eddigieket már csak azzal lehet megkoronázni, hogy saját subversionnal (2.6.15.4) látjuk el a kernelünk:

  1. ehhez először készítsünk egy másolatot az eredeti Makefileról mondjuk Makefile-pear1 néven
  2. majd a másolat "EXTRAVERSION = .4" részét írjuk át ilyenre: "EXTRAVERSION = -pear1"
  3. majd lépjünk vissza egy könyvtárszintet és gyártsuk le a két állomány különbségéből a patchet
    • /usr/src# diff -urN linux-2.6.15/Makefile linux-2.6.15/Makefile-pear1 > linux-2.6.15/patches/2.6.15-pear1.diff
  4. lépjünk vissza a kernel forráskönyvtárába és természetesen teszteljük le: patch -i patches/2.6.15-pear1.diff --dry-run
  5. ha minden oké, akkor tegyük be a "patches/" könyvtárba, jegyezzük be a "series"be és nyomjuk fel a "quilt"tal (és töröljük a Makefile-pear1-t)

Még egy kis trükk, hogy a quilt minden alap kapcsolóját kipróbáljuk: a -q hatására csendes módba vált és csak a patchek neveit írja ki

  • quilt pop -qa: leszedi az össes patchet minimális üzenettel
  • quilt pusf -qa

Patchek összeolvasztása

Elvileg kész a patchset, két féleképp hozható hordozható formába:

  • összetömörítjük a "series" és a "patches/" tartalmát
  • egy állományból álló patchsetet készítünk

Az előbbi elég egyértelmű, nézzük az utóbbi lépéseit:

  1. quilt pop -aq : biztos, hogy vanilla kernelünk legyen
  2. quilt snapshot -d : az előző snapshot biztos el legyen távolítva
  3. quilt snapshot : lementjük a forrás jelenlegi állapotát (pontosabban azt, hogy mely patchek vannak beolvasztva)
  4. quilt push -aq : felnyomjuk az össze patchet
  5. quilt diff --snapshot > linux-2.6.15-pear1.patch : az előző és a jelenlegi állapot különbségét lementjük egy állományba
  6. quilt pop -aq : vissza a vanilláig
  7. quilt snapshot -d : snapshot törlése

Egy utolsó tipp: a "quilt" a .pc/ könyvtárt használja a patchek nyomon követésére:

  • .pc/applied-patches : felrakási sorrendben a jelenlegi patchek
  • .pc/patch_név/ : a patch által megváltoztatott állományok a patchelés előtti állapotban

Ennyi, lehet repülni. (C) CoVboy

Kapcsolódó szócikkek